OpenGL Texture Wrapping Filtering Mipmap 텍스처 래핑 필터링 밉맵[Learn OpenGL 쉬운 번역]

728x90
반응형
※ 본 포스팅은 learnopengl.com을 번역 및 가감한 포스팅이며, learnopengl에서는 번역 작업 참여를 적극 장려하고 있습니다!
아래 링크에서 원문을 확인할 수 있습니다.

 

Textures

이전에 object에 색상을 추가하여 삼각형을 그렸습니다. 더 현실적으로 꾸미기 위해서 기존에 만들어 놓은 texture를 적용하는 방법이 있는데. texture는 일반적으로 2D 이미지로 구성됩니다. 이걸 object에 씌우면 object의 겉모습의 무늬가 바뀝니다. 

 

이렇게 texture를 적용하면 vertex를 더 추가하지 않고도 object를 디테일하게 보이는 효과를 줍니다. 

 

이미지 말고도 texture 데이터를 대량으로 저장해서 shader로 전송해서 사용할 수 있지만 나중에 다루도록 합니다.

texture 이미지를 적용하면 아래와 같이 삼각형의 무늬가 바뀝니다.

삼각형에 텍스처를 매핑하기 위해서는 삼각형의 각 정점이 텍스처의 어느 부분에 해당하는지를 지정해야 합니다. 각 정점에 texture 이미지에서 샘플링할 부분을 지정하는 texture coordinate와 mapping시켜야합니다. 나머지 fragment는 보간으로 자도 처리되죠. 

 

texture coordinate는 x,y 축에서 0~1 범위 값을 가집니다. texture coordinate 값으로 texture가 되는 2D 이미지의 색상을 가져오는 걸 sampling이라 합니다. texture coordinate는 이미지의 좌하단 모서리부터 (0,0) 우상단이 (1,1)입니다. 이미지는 texture coordinate로 mapping해봅시다. 

 

삼각형의 텍스처 좌표를 지정하기 위해 3개의 텍스처 좌표 지점을 설정합니다. 삼각형의 왼쪽 하단을 텍스처의 (0,0)으로, 삼각형의 오른쪽 하단을 텍스처의 (1,0)으로, 삼각형의 중앙 상단을 텍스처의 (0.5,1.0)으로 설정합니다. 이렇게 3개의 texture coordinate만 vertex shader에 전달하면 vertex shader는 이를 fragment shader로 전달해서 나머지 pixel 위치들은 texture의 어디 좌표인지 보간해서 처리합니다.

 

float texCoords[] = {
    0.0f, 0.0f,  // 왼쪽 하단 모서리
    1.0f, 0.0f,  // 오른쪽 하단 모서리
    0.5f, 1.0f   // 상단 중앙 모서리
};

이렇게 texture sampling은 중요한 좌표만 지정해주면 나머지는 유연하게 보간처리를 해줍니다. OpenGL은 어떻게 sampling할지 지정할 수 있는데요.

 

Texture Wrapping

texture coordinate의 범위는 (0,0) ~ (1,1) 까지입니다. 이걸 벗어나면 처리하는 방법은 여러 설정이 있는데, 기본적으로는 이미지를 반복해서 넣습니다. 좌표가 영역을 넘어가면 정수부분은 무시하고 소수부분만 보고 반복해서 처리하는 것이죠. 이것 말고도 다음과 같은 옵션도 있습니다.

 

 

  • GL_REPEAT: 텍스처의 기본 동작입니다. 텍스처 이미지를 반복합니다.
  • GL_MIRRORED_REPEAT: GL_REPEAT와 동일하지만, 반복 시 이미지가 거울처럼 반전됩니다.
  • GL_CLAMP_TO_EDGE: 좌표를 0과 1 사이로 클램프(고정)합니다. 이로 인해 더 높은 좌표는 가장자리에 고정되어, 가장자리가 늘어난 패턴이 생성됩니다.
  • GL_CLAMP_TO_BORDER: 범위를 벗어난 좌표는 사용자가 지정한 경계 색상으로 처리됩니다.

기본 범위를 벗어난 좌표를 넘겨주면 위 네 가지 중 설정한 옵션대로 texture를 출력해줍니다.

 

https://learnopengl.com/Getting-started/Textures

 

 

위 네 가지 옵션은 glTexParameter* 함수를 사용해서 texture coordinate의 축 하나씩 설정할 수 있습니다. 2D texture라면 s,t 좌표를하고 3D texture라면 s,t,r 세 개를 이용합니다. (s,t,r은 x,y,z, 에 대응되는 겁니다)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

 

 

glTexPrameter의 매개변수를 순서대로 봅시다. 첫 번째는 texture target인데 현재는 2D texture를 사용하므로 GL_TEXTURE_2D로 되어었습니다. 두 번째에서 texture 축을 선택합니다. 세 번째에서는 wrapping mode를 선택합니다. 코드에서는 GL_MIRRORED_REPEAT를 통해서 영역을 벗어나면 반복하도록 했습니다.

 

만약 모드가 GL_CLAMP_TO_BORDER라면, 경계색도 지정해야됩니다. 

지정할 때 glTexParameter 함수 종류 중 fv(floating vector)를 써서 GL_TEXTURE_BORDER_COLOR 옵션으로 색상값 float 배열을 넘겨줍니다.

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

 

Texture Filtering

texture coordinate는 해상도가 달라지면 소수점의 값으로 그 비율을 정합니다. opengl에서 texture가 화면의 pixel에 대응되는 texture 상에서의 픽셀을 texel이라고 하는데, 이 texel 좌표에 texture를 어떻게 mapping할지 정해야합니다. texture는 저해상도인데 object가 크면 해상도가 깨지겠죠? 그래서 opengl에서 texture filtering도 할 수 있습니다. filtering은 그 방식이 굉장히 많은데 여기서는 대표적으로 GL_NEAREST, GL_LINEAR를 다뤄봅니다.

 

GL_NEAREST는 opengl에서 기본으로 적용하는 filtering입니다. GL_NEAREST는 texture 좌표가 있으면 이 위치에서 가장 가까운 texel을 선택해서 적용합니다. 아래 그림을 보면 texture 좌표는 왼쪽 위 texel의 중심과 가장 가깝기 때문에 이걸로 sampling해서 색을 정합니다.

GL_LINEAR는 주변 texel 색상을 어느정도 보간하는 방식입니다. texture 좌표가 있으면 인접한 texel들이 있고, 그 중심이 가까울 수록 많이 반영해서 색을 보간해서 sampling합니다. 

이걸 실제 이미지로 확인해보면 이렇습니다. 낮은 해상도의 이미지를 큰 해상도의 object에 mapping해서 filtering된 결과입니다.

GL_NEAREST는 texture의 픽셀이 보이는데, GL_LINEAER는 좀 더 부드럽죠? 이건 취향에 따라서 픽셀 느낌을 내고 싶을 수도 있으니 다르게 사용하면 될 것 같습니다.

 

texture filtering의 경우 magnifying(확대)되는 경우 minifying(축소)되는 경우 scaling될 때 별도로 설정가능합니다. 텍스처가 축소될 때는 NEAREST, 확대 될 때는 LINEAR를 사용하고 싶다면 glTexParameteri로 다음과 같이 하면 됩니다.

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

 

Mipmaps

공간에 object가 엄청 많고, 모든 object에 texture가 mapping되어있다고 합시다. 가까이 있건 멀리 있어서 잘 안보이건 똑같이 texture가 고해상도로 붙어있습니다. 그러면 멀리 있으면 fragment shader에서 화면에 띄울 색상을 계산할 때 어떤 색을 가져와야하는지도 애매하고, fragment shader에서 적용된 색상이 object에서 적용되었을 때 부자연스러운 아티팩트가 생길 수 있습니다. 또 이렇게 화면에 띄울 픽셀이 적은데 고해상도 texture를 사용하면 메모리도 낭비됩니다.

 

그래서 미리 texture이미지를 scaling해서 mipmaps(밉맵)이라는 걸 이용합니다. texture를 두 배 기준으로 작게 만들어서 따로 저장하는 겁니다. 만약 texture가 적용되는 object까지의 거리가 특정 값 이상으로 넘어가면 거기에 적합한 mipmap texture를 적용합니다. 어차피 멀리 있는 object라서 texture 해상도가 낮아도 티가 안납니다. 또 texel sampling 과정에 들어가는 cache 메모리도 줄어들어서 효율적입니다.

 

texture 이미지마다 mipmap texture를 하나하나 생성하는게 번거로우니 opengl에서 texture에 대해 glGenerateMipmap으로 자동으로 mipmap을 생성할 수 있습니다.

 

렌더링을 하는 도중에 mipmap 레벨을 변경하면 부자연스러운 아티팩트가 생길 수 있습니다. texture filtering에서 본 것처럼 mipmap에도 filtering을 써서 이런 현상을 줄일 수 있습니다. 종류는 기본 NEAREST, LINEAR가 있고 mipmap 레벨을 전환할 때 옵션은 다음 네 가지가 있습니다.

 

 

  • GL_NEAREST_MIPMAP_NEAREST: 픽셀 크기에 가장 가까운 mipmap을 선택하고, 텍스처 샘플링을 위해 근접 보간(nearest neighbor interpolation)을 사용합니다.
  • GL_LINEAR_MIPMAP_NEAREST: 가장 가까운 mipmap 레벨을 선택하고, 해당 레벨을 선형 보간(linear interpolation)으로 샘플링합니다.
  • GL_NEAREST_MIPMAP_LINEAR: 픽셀 크기에 가장 가까운 두 mipmap 을 선형 보간하여, 보간된 레벨을 근접 보간으로 샘플링합니다.
  • GL_LINEAR_MIPMAP_LINEAR: 가장 가까운 두 mipmap을 선형 보간하여, 보간된 레벨을 선형 보간으로 샘플링합니다.

옵션을 보면 앞의 필터링 종류는 선택한 mipmap 레벨을 sampling할 때 적용하는 filtering이고, 뒤의 필터링 종류는 픽셀 크기에 알맞는 mipmap 레벨을 선택하는 방법에 대한 filtering입니다.

texture filtering에서 했던 것처럼 glTexParameteri로 filtering 방법을 설정합니다. 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

 

여기서 magnifying 옵션을 mipmap 옵션으로 설정하는 것은 아무런 효과가 없습니다. 왜냐하면 mipmap은 원본 texture에서 texture를 minifying하는 경우에만 사용되는 것이기 때문이죠. magnifying에서는 mipmap이 사용되지 않기에 magnifying에 mipmap filteirng 을 지정하면 GL_INVALID_ENUM 오류가 납니다. 

 

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유