Graphics Programming
텍스처(Texture) 본문
텍스처
- 셰이더가 읽고 쓸 수 있는 구조화된 저장 형태
- 주로 이미지 데이터를 저장하는 데 쓰임
사용법
1. 이름을 생성한다
2. 텍스처 타겟에 그 이름을 바인딩한다
3. 원하는 이미지 크기를 명시한다
종류 - 1D, 2D, 3D, rectangle
텍스처 읽기
- 텍스처는 샘플러 변수(sampler variable)로 표현된다
- 2D 텍스처 => sampler2D
uniform sampler2D s;
out vec4 color;
void main() {
color = texelFetch(s, ivec2(gl_FragCoord.xy), 0);
}
sampler1D, sampler2D, ... => floating-point
prefix i => integer(signed)
prefix u => unsigned integer
텍스처 읽기 제어 - 래핑wrapping, 필터링filtering 모드
매개변수들은 sampler 개체에 저장된다
glGenSamplers(GLsizei n, GLuint *samplers)
glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
sampler 개체를 타겟에 바인딩하지 않아도 직접 수정할 수 있다
샘플러 개체를 텍스처 유닛에 바인딩하기
glBindSampler(GLuint uint, GLuint sampler)
각 텍스처는 샘플러 개체를 내장한다
void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
void glTexParameteri(GLenum target, GLenum pname, GLint param)
여러 텍스처 사용
- 샘플러 유니폼을 여러 개 생성한다
- 각각 다른 텍스처 유닛을 참조하도록 설정한다
- 몇 개까지 지원하는가?
GLint maxUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits);
=> 셰이더 스테이지들 중 임의의 한 시점에서 접근 가능한 텍스처 유닛 최대 개수
- 텍스처를 텍스처 유닛에 바인딩하기: active texture unit selector를 변경해야 한다
glActiveTexture(GL_TEXTURE0 + offset)
- GL_TEXTURE1 ~ 31까지는 정의되어 있음
- 샘플러 유니폼들이 다른 유닛들을 참조하게 하는 방법
1. glUniform1i() with glGetUniformLocation()
2. layout(binding = 0) uniform sampler2D foo // 추천
텍스처 필터링: 실제로는 텍셀과 픽셀이 일대일로 매칭될 일이 거의 없다
- texelFetch(): 특정 정수 텍스처 좌표에서 단일 텍셀을 가져온다
- 더 유연한 함수로 texture()가 있다
- 텍스처 늘이기 = maginifcation -> GL_TEXTURE_MAG_FILTER
- 텍스처 줄이기 = minification -> GL_TEXTURE_MIN_FILTER
- 기본 필터: GL_NEAREST, GL_LINEAR
* 기본 필터링은 밉맵 없이는 작동하지 않는다
- glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
밉매핑
- 일반적인 텍스처 매핑의 흔한 문제점
1. scintillation (계단현상)
2. performance (띄엄띄엄 하는 추출)
물체는 작을 때 텍스처는 클 때
- 밉매핑 수준 결정
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4)
밉맵 필터링
- minification의 경우
- GL_NEAREST_MIPMAP_NEAREST - nearest mipmap, nearest neighbor sampling
- GL_NEAREST_MIPMAP_LINEAR - 밉맵간 보간, 최단 이웃 샘플링
- GL_LINEAR_MIPMAP_NEAREST
- GL_LINEAR_MIPMAP_LINEAR
- magnification의 경우 GL_NEAREST와 GL_LINEAR만 가능
- GL_LINEAR_MIPMAP_LINEAR를 trilinear 밉매핑이라고 부르기도 한다
밉맵 얻는 방법
- 모든 밉맵 수준을 직접 그린다
- OpenGL이 생성하도록 한다: glGenerateMipmap(GLenum target)
텍스터 wrap
- glSamplerParameteri(param, value)
- param: GL_TEXTURE_WRAP_S,T,R
- value: GL_REPEAT, MIRRORED_REPEAT, CLAMP_TO_EDGE, CLAMP_TO_BORDER
- S는 1D,2D,3D에, T는 2D,3D에, R은 3D에 영향을 준다
- clamp to border의 경우 색상 설정은 glSamplerParameterfv()에 GL_TEXTURE_BORDER_COLOR를 인자로
array texture: 여러 개의 1D, 2D, 큐브맵 이미지를 하나의 텍스처 개체에 적재
- 둘 이상의 이미지를 하나의 텍스처에 담기는 새로운 개념이 아니다
- 밉매핑: 각 밉 수준은 별개의 이미지
- 큐브매핑: 각 면이 고유의 이미지와 밉 수준을 가진다
- 그럼 텍스처 배열은 무엇인가?
- 텍스처 이미지의 배열이 하나의 텍스처 개체에 바인딩되고 셰이더는 인덱스를 통해 접근한다
- 종류: 1D, 2D, 큐브맵 배열 텍스처. 단 3D 배열 텍스처는 없음
- 2D 배열 텍스처와 3D 텍스처의 차이점
- 배열 텍스처의 레이어 사이에는 필터링이 적용되지 않는다
- 2D 배열 텍스처 불러오기
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 8, GL_RGBA8, 256, 256, 100);
for(int i=0; i<100; i++){
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, 256, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, image_data[i]);
}