Texture Wrapping
텍스쳐의 좌표 범위는 (0,0) 에서 (1,1) 이다.
만약 이 범위 밖의 좌표를 지정할 경우, OpenGL은 기본적으로 텍스쳐를 반복한다.
만약 단순 반복하는게 아니라 대칭반복하거나, 클램핑하거나, 지정한 색으로 채우고 싶을 경우, 아래와 같은 다양한 옵션을 사용할 수 있다.
GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
이 설정값은 텍스쳐를 컨텍스트에 바인딩한 이후, 설정값을 넣는다.
x축, y축에 대해 각각 설정을 지정해야 하는데, 아래와 같이 glTexParameteri 함수를 사용하여 지정할 수 있다.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GL_TEXTURE_WRAP_S, _T 부분이 X, Y 축을 지정하는 부분이다.
X축이 S, Y축이 T이다.
만약 GL_CLAMP_TO_BORDER 옵션을 지정하고 싶다면, 아래와 같이 사용해야 한다.
float borderColor[] = { 1.0, 1.0, 0.0, 1.0f };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
X, Y 축에 대해 Border 를 사용하는 것을 지정한 뒤, BORDER 색상을 따로 지정한다.
Texture Wrapping 실습
먼저 아래와 같이 사각형에 이미지를 그리는 형태의 코드를 작성했다.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Shader.h"
#include "stb_image.h"
#include <iostream>
float vertice[] = {
-0.5, -0.5, 1.0, 0, 0,
0.5, -0.5, 1.0, 1, 0,
-0.5, 0.5, 1.0, 0, 1,
0.5, 0.5, 1.0, 1, 1
};
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, "texture wrapping", NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
/**
* VBO, VAO, EBO
*/
unsigned int VBO, VAO, EBO;
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("4.1.texture.vs", "4.1.texture.fs");
/**
* Texture
*/
unsigned int texture;
int width, height, componentCount;
unsigned char* data;
data = stbi_load("wall.jpg", &width, &height, &componentCount, 0);
if (!data) {
std::cout << "image loading fail!\n";
}
// texture 생성 & Binding
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Image 연결
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D); // 기본값으로 유니폼 sampler2D 변수에 텍스쳐가 있음.
while (!glfwWindowShouldClose(window)) {
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
}
실행 결과는 아래와 같다.
이제 이 이미지에 대해 Texture Wrapping 설정값을 넣고, 텍스쳐 좌표를 임의로 바꿔보자.
우선 이렇게 좌표값을 0~1 범위가 아니라 -1~2 범위로 작성했다.
실행결과는 아래와 같다.
범위를 벗어난 이미지에 대해 자동으로 반복적으로 그림을 그리도록 설정되었다.
이는 TextureWrapping 기본값이 GL_REPEAT 이기 때문이다.
이 설정을 한번 바꿔서 적용해보자.
텍스쳐를 바인딩한 뒤, 설정값에 X, Y축 모두 MIRRORED_REPEAT 을 적용해보았다.
실행결과는 아래와 같다.
뭔가 반전되면서 반복이 이루어졌다.
이번엔 clamping 해보자.
코드는 위와 같이 작성했다.
실행결과이다. 뭔가 한 나라의 국기 모양같다.
마지막으로 GL_CLAMP_BORDER를 사용해보자.
설정을 X, Y 모두 Border 로 넣고, 색상값은 노란색으로 지정했다.
실행결과는 위와 같다.
만약 X, Y 축에 다른 설정을 적용하면 어떻게 될까?
X축에만 MIRRORED_REPEAT을 적용해보았다.
이렇게 나온다.
Texture Filtering
텍스쳐의 좌표는 어떤 실수값도 될 수 있다.
따라서 어떤 임의의 텍스쳐 좌표를 찍었을 때, 그 좌표의 위치는 이미지 픽셀의 어떤 어중간한 위치가 될 수 있다.
색상이 있는 사각형 4개가 각각의 이미지 픽셀이고, 저 십자표시가 텍스쳐 좌표 위치이다.
(이 텍스쳐 이미지의 픽셀을 '텍셀' 이라고 한다.)
이때 이렇게 어중간한 위치를 찍은 것에 대해 대해서 실제 화면 픽셀에 그릴 때 어떻게 그릴지를 결정하는 것이 Texture Filtering 이다.
이는 큰 객체에 저해상도 텍스쳐를 매핑할 때, (즉, 작은 이미지를 넓은 객체에 씌울 때) 중요한 이슈가 된다.
(이미지를 확대하는 것을 생각하면 된다.)
Texture Filtering 옵션은 아래와 같은 방식들이 있다.
Nearest Neighbor 방식은, 가장 가까운 픽셀의 색을 그대로 사용하는 것이다.
GL_NEAREST 옵션으로 설정한다.
Point Filtering 옵션이 있다. (설명이 없음..)
Linear Filtering, Bilinear Filtering 텍스쳐 좌표 주위의 텍셀 색상들을 interpolation 한다. (섞는다)
텍스쳐 좌표와 가까운 텍셀일 수록 해당 색상의 weight 가 커져 더 많이 섞인다.
(아마 리니어는 1D 가로, 세로만 보고 섞는 거고, bilinear는 2D 영역으로 확대해서 섞는게 아닐까.. 추측한다.)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
텍스쳐 필터링은 위 코드로 옵션을 설정한다.
MIN_FILTER는 텍스쳐를 축소했을 때, 어떤 필터링 옵션을 사용할 것인지 지정하고,
MAG_FILTER는 텍스쳐를 확대했을 때, 어떤 필터링 옵션을 사용할 것인지 지정한다.
세번째 파라미터에는 확대, 축소시 mipmap을 어떻게 사용할지 지정한다.
그렇다고 한다.
MipMap
카메라로 공간에 객체를 볼 때, 거리가 먼 객체의 이미지 해상도와, 거리가 가까운 객체의 이미지 해상도가 같다면 메모리가 낭비된다. 거리가 먼 객체의 이미지를 그릴 때는 더 적은수의 Fragment로 표현해도 충분하기 때문이다.
MipMap은 거리 level 에 따라서 이미지를 반씩 줄인, 크기별 이미지의 집합이다.
거리가 멀어지면 저화질의 테스쳐를 매핑해서 메모리를 효율적으로 사용한다.
Texture Filtering 실습
우선 이미지를 10배 확대해보자.
GL_LENEAR 옵션을 설정해보았다.
이렇게 나온다.
반면 Nearest 를 사용하면
이렇게 사각형 격자모양으로 이미지가 그려진다.
겉보기에는 Lenear가 더 좋아보인다.
'CS > HCI 윈도우즈프로그래밍' 카테고리의 다른 글
[OpenGL] 13. Transformation (1) - 변환의 기본 개념 (0) | 2024.04.17 |
---|---|
[OpenGL] 12. Shader (8) - 여러 Texture 생성하기 (0) | 2024.04.14 |
[OpenGL] 10. Shader (6) - Texture (0) | 2024.04.11 |
[OpenGL] 9. Shader (5) - 직사각형에 실시간으로 변하는 색상 입히기 (GLFW, GLAD) (0) | 2024.04.09 |
[OpenGL] 8. Shader (4) - GLSL (0) | 2024.04.09 |