Sampler
GLSL 에서 텍스쳐 객체를 저장하기 위한 내장 데이터 타입 (일종의 컨테이너) 이다.
텍스쳐 타입에 따라 sampler1D, sampler2D, sampler3D 등으로 분류되며, uniform 변수로 선언한다.
기본적으로 디폴트값이 정해져 있어서, 텍스쳐를 하나만 바인딩하는 경우에는 직접 유니폼 변수에 값을 등록하지 않아도 바로 사용할 수 있다.
텍스쳐를 유니폼 변수에 직접 등록하기
텍스쳐를 유니폼 변수에서 사용할 때는 텍스쳐의 위치에 해당하는 정수값을 넘겨주게 된다.
이러한 텍스쳐의 위치를 texture unit 이라고 한다.
이 텍스쳐 유닛의 기본값은 0이다. (그래서 하나를 바인딩할 때는 바로 가져다 사용할 수 있는 것)
텍스쳐 유닛을 사용하는 이유는 사용자가 셰이더로 하여금 1개 이상의 텍스쳐를 사용할 수 있도록 만들기 위함이다.
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
우선 원래 등록하던대로 텍스쳐를 만들어서 이미지까지 연결시킨다.
원래는 이렇게만 하면 0번 위치에 알아서 바인딩이 되었다.
// Texture 2 loading
data = stbi_load("pepe.jpg", &width, &height, &componentCount, 0);
unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
두번째 텍스쳐도 이렇게 불러온다.
shader.use();
glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0);
glUniform1i(glGetUniformLocation(shader.ID, "texture2"), 1);
다음으로는 텍스쳐를 uniform 변수로 등록한다.
shader.use() 를 렌더링 루프 밖에서 호출하는 이유는 이렇게 셰이더를 활성화해두어야 등록이 되기 때문이라고 한다.
shader.setInt("texture2", 1);
셰이더 클래스를 사용하는 경우, 유니폼 변수를 이렇게 등록할 수도 있다.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
shader.use();
마지막으로 렌더링 루프에서 shader.use() 를 호출하기 전에 Texutre 를 각 할당한 인덱스별로 활성화하고, 바인딩까지 하면 된다.
아래는 실행 결과이다.
소스코드
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "stb_image.h"
#include "Shader.h"
float vertice[] = {
-0.5, -0.5, 1.0, 0.0, 0.0, // 왼쪽 아래
0.5, -0.5, 1.0, 1.0, 0.0, // 오른쪽 아래
-0.5, 0.5, 1.0, 0.0, 1.0, // 왼쪽 위
0.5, 0.5, 1.0, 1.0, 1.0, // 오른쪽 위
};
unsigned int indice[] = {
0, 1, 2,
1 ,2, 3
};
int main() {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "multiple texture", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
// VBO, EBO, VAO
unsigned int VBO, EBO, VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertice), vertice, GL_STATIC_DRAW);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indice), indice, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (void*)(sizeof(float)*3));
glEnableVertexAttribArray(1);
// Shader
Shader shader("7_texture.vs", "7_texture.fs");
// Texture 1 loading
unsigned char* data;
int width, height, componentCount;
data = stbi_load("container.jpg", &width, &height, &componentCount, 0);
unsigned int texture1;
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
// Texture 2 loading
data = stbi_load("pepe.jpg", &width, &height, &componentCount, 0);
unsigned int texture2;
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);
shader.use();
glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0);
/*glUniform1i(glGetUniformLocation(shader.ID, "texture2"), 1);*/
shader.setInt("texture2", 1);
while (!glfwWindowShouldClose(window)) {
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
glEnable(GL_LINE_SMOOTH);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteVertexArrays(1, &VAO);
glfwTerminate();
}
#version 330 core
in vec2 TexCoord;
out vec4 aColor;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main() {
//aColor = vec4(0.7, 0.7, 0.7, 1.0);
aColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
fragment shader 코드이다.
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
vertex shader 소스코드이다.
'CS > HCI 윈도우즈프로그래밍' 카테고리의 다른 글
[OpenGL] 14. Transformation (2) - 복합 변환 (0) | 2024.04.18 |
---|---|
[OpenGL] 13. Transformation (1) - 변환의 기본 개념 (0) | 2024.04.17 |
[OpenGL] 11. Shader (7) - Texture Wrapping, Filtering, MipMaps (1) | 2024.04.12 |
[OpenGL] 10. Shader (6) - Texture (0) | 2024.04.11 |
[OpenGL] 9. Shader (5) - 직사각형에 실시간으로 변하는 색상 입히기 (GLFW, GLAD) (0) | 2024.04.09 |