โ Texture Unit
ํ ์ค์ฒ ์ ๋์ ํ๋ ์ด์์ ํ ์ค์ฒ ๊ฐ์ฒด๋ฅผ ๋ฐ์ธ๋ฉ ํ ์ ์๋ ์ฌ๋กฏ์ผ๋ก ์ฌ๋ฌ ํ ์ค์ฒ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค.
glActiveTexture(GL_TEXTURE0); // ํ
์ค์ฒ ์ ๋์ ํ์ฑํ
glBindTexture(GL_TEXTURE_2D, texture); // ํ์ฑํ ๋ ์ ๋์ ํด๋น ํ
์ค์ฒ๋ฅผ ๋ฐ์ธ๋ฉ
* GL_TEXTURE0 ์ ๋์ ํญ์ ๊ธฐ๋ณธ์ผ๋ก ํ์ฑํ ๋๋ค.
* GL_TEXTURE0 ๋ถํฐ GL_TEXTURE15 ๊น์ง ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ์์๋๋ก ์ ์ธ๋์ด ์์ด GL_TEXTURE + n ๊ณผ ๊ฐ์ ํ์์ผ๋ก๋ ์ ๊ทผํ ์ ์๋ค.
- Fragment Shader
Fragment Shader์์ ํ
์ค์ฒ ์ ๋์ ์ํ๋งํ๋ค.
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
* mix ํจ์๋ ๋ ๊ฐ์ ๊ฐ์ ๋ฐ๊ณ ์ธ ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ ์ ํ ๋ณด๊ฐํ๋ค.
โ ์ฌ๋ฌ ํ ์ค์ฒ ์ ์ฉ
โ ๋ ๋ฒ์งธ ํ ์ค์ฒ ๋ก๋ ๋ฐ ์์ฑ
unsigned char *data = stbi_load("๋ ๋ฒ์งธ ์ด๋ฏธ์ง ํ์ผ ๊ฒฝ๋ก", &width, &height, &nrChannels, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
* .png ํ์ผ ๋ก๋ ์ GL_RGBA๋ฅผ ์ฌ์ฉํ์ฌ alpha ์ฑ๋์ ํฌํจํ๊ณ ์๋ ์ด๋ฏธ์ง ๋ฐ์ดํฐ์์ ๋ช ์ํด์ผ ํ๋ค.
โ ๋ ๊ฐ์ ํ ์ค์ฒ๋ฅผ ํ ์ค์ฒ ์ ๋์ ๋ชจ๋ ๋ฐ์ธ๋ฉ
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
โ ๊ฐ Shader Sampler๊ฐ ์ํ๋ ํ ์ค์ฒ ์ ๋์ ๋ช ์
ourShader.use(); // ์
ฐ์ด๋ ํ๋ก๊ทธ๋จ ํ์ฑํ
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); // ์ง์ ์ค์
ourShader.setInt("texture2", 1); // ํน์ shader ํด๋์ค๋ฅผ ํ์ฉ
* uniform ์ค์ ์ shader program์ ํ์ฑํํด์ผ ํ๋ค.
์ด๋๋ก ๋ ๋ํ๋ฉด ํ
์ค์ฒ๊ฐ ์ํ ๋ฐ์ ๋์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค (OpenGL์ด y์ถ์ 0.0 ์ขํ๋ฅผ ์ด๋ฏธ์ง์ ํ๋จ์ผ๋ก ๊ฐ์ฃผํ๋ ๋ฐ๋ฉด, ์ผ๋ฐ์ ์ผ๋ก ์ด๋ฏธ์ง๋ y์ถ์ 0.0 ์ขํ๊ฐ ์๋จ์ ์์นํ๊ธฐ ๋๋ฌธ์ ๋ฐ์)
→ ์ด๋ฏธ์ง ๋ก๋ ์ ์ํ ๋ฐ์ ์ํค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ํด๊ฒฐํ๋ค.
stbi_set_flip_vertically_on_load(true);
โ ์์ค ์ฝ๋
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <Shader.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
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;
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, 1.0f, 1.0f, // ์ฐ์ธก ์๋จ
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.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, 1.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);
// ๋ฐฐ๊ฒฝ ๋ ๋
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();
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);
}
}
// ์๋์ฐ ์ฌ์ด์ฆ ๋ณ๊ฒฝ ์ ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
โ ๋งํฌ
'๐จ Graphics > ๐ต OpenGL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [OpenGL] ํ๋ ฌ (Matrix) (0) | 2024.07.30 |
|---|---|
| [OpenGL] ๋ฒกํฐ (Vector) (0) | 2024.07.30 |
| [OpenGL] Texture ์ ์ฉ (0) | 2024.07.28 |
| [OpenGL] Texture ๋ก๋ (0) | 2024.07.28 |
| [OpenGL] Shader (2) | 2024.07.24 |