수색…


텍스처링의 기초

텍스처는 특정 데이터 항목뿐 아니라 여러 항목을 혼합 (보간)하는 샘플 지점에 대한 편리한 액세스를 허용하는 데이터 저장소의 한 형태입니다.

OpenGL에서 텍스쳐는 많은 것들에 사용될 수 있지만 가장 일반적으로 이미지를 폴리곤 (예 : 삼각형)에 매핑합니다. 텍스처를 삼각형 (또는 다른 다각형)에 매핑하려면 텍스처의 어느 부분에 해당하는지 각 꼭지점에 알려야합니다. 우리는 다각형의 각 꼭지점에 텍스처 좌표를 할당하고 그 다각형의 모든 단편 사이에 보간됩니다. 텍스처 좌표는 일반적으로 아래 이미지와 같이 x 및 y 축에서 0에서 1까지입니다.

텍스처 좌표

이 삼각형의 텍스처 좌표는 다음과 같습니다.

GLfloat texCoords[] = {
    0.0f, 0.0f,  // Lower-left corner  
    1.0f, 0.0f,  // Lower-right corner
    0.5f, 1.0f   // Top-center corner
};

이러한 좌표를 VBO (정점 버퍼 객체)에 넣고 셰이더에 대한 새 특성을 만듭니다. 버텍스 위치에 적어도 하나의 속성을 이미 가져야하므로 텍스쳐 좌표에 대해 다른 속성을 생성하십시오.


텍스처 생성하기

우선 할 일은 unsigned int 텍스처에 저장 될 ID에 의해 참조 될 텍스처 객체를 생성하는 것입니다 :

GLuint texture;
glGenTextures(1, &texture); 

그 후에는 이후의 모든 텍스처 명령이이 텍스처를 구성하도록 바인드해야합니다.

glBindTexture(GL_TEXTURE_2D, texture); 

이미지로드 중

이미지를로드하려면 자신 만의 이미지 로더를 만들거나 Java C ++ 또는 TWL의 PNGDecoder 에서 SOIL (Simple OpenGL Image Library)과 같은 이미지로드 라이브러리를 사용할 수 있습니다.

SOIL로 이미지를로드하는 예는 다음과 같습니다.

int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB); 

이제이 이미지를 텍스처 오브젝트에 할당 할 수 있습니다 :

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

그런 다음 텍스처 객체를 바인딩 해제해야합니다.

glBindTexture(GL_TEXTURE_2D, 0); 

텍스처 좌표의 랩 파라미터

위에서 볼 수 있듯이 텍스처의 왼쪽 아래 모서리에는 UV (st) 좌표 (0, 0)가 있고 텍스처의 오른쪽 위 모서리에는 좌표 (1, 1)이 있지만 메쉬의 텍스처 좌표는 모든 범위. 이를 처리하기 위해 텍스처 좌표가 텍스처에 래핑되는 방식을 정의해야합니다.

텍스처 좌표의 랩 파라미터는 GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_TGL_TEXTURE_WRAP_R 사용하여 glTextureParameter 로 설정할 수 있습니다.

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

가능한 매개 변수는 다음과 같습니다.

  • GL_CLAMP_TO_EDGE 는 텍스처 좌표가 [1 / 2N, 1 - 1 / 2N] 범위에 고정되도록합니다. N 은 방향의 텍스처 크기입니다.

  • GL_CLAMP_TO_BORDER 동일하지 GL_CLAMP_TO_EDGE 하지만 클램핑의 경우, 페치 된 텍셀 데이터에 의해 지정된 색으로 치환 GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT 는 텍스처 좌표의 정수 부분을 무시하도록합니다. 텍스처가 바둑판 식으로 배열되어 있습니다.

반복되는 질감

  • GL_MIRRORED_REPEAT : 텍스처 좌표의 정수 부분이 짝수이면 무시됩니다. 반면, 텍스처 좌표의 정수 부분이 홀수 인 경우 텍스처 좌표는 1 - frac (s)로 설정 됩니다. fract (s) 는 텍스처 좌표의 소수 부분입니다. 이로 인해 텍스처가 두 번째로 미러링 됩니다.

거울 텍스처

  • GL_MIRROR_CLAMP_TO_EDGEGL_CLAMP_TO_EDGE 에서와 같이 클램핑 될 좌표를 텍스쳐의 하나의 reptition에 대해 GL_MIRRORED_REPEAT 대해 텍스트 좌표가 반복되도록합니다.

GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_TGL_TEXTURE_WRAP_R 의 기본값은 GL_REPEAT 입니다.


텍스처 적용

마지막으로 수행 할 작업은 그리기 호출 전에 텍스처를 바인딩하는 것입니다.

glBindTexture(GL_TEXTURE_2D, texture);

텍스처 및 프레임 버퍼

텍스처의 이미지를 프레임 버퍼에 첨부 할 수 있으므로 해당 텍스처에 직접 렌더링 할 수 있습니다.

glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
                       GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D,
                       texture,
                       0);

참고 : 정의되지 않은 동작을 호출하기 때문에 동일한 렌더링 작업에서 동일한 텍스처를 읽고 쓸 수 없습니다. 그러나 당신은 이것을위한 render 호출 사이에 glTextureBarrier() 사용할 수 있습니다.

텍스처 데이터 읽기

glGetTexImage 함수를 사용하여 텍스처 데이터를 읽을 수 있습니다.

char *outBuffer = malloc(buf_size);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              outBuffer);

참고 : 텍스처 유형 및 형식은 예를 들어, 다를 수 있습니다.

PBO 사용

버퍼를 GL_PIXEL_UNPACK_BUFFER 바인드하면 glTexImage2Ddata 매개 변수가 해당 버퍼로 오프셋됩니다.

즉, glTexImage2D는 반환 할 수 있기 전에 모든 데이터가 응용 프로그램의 메모리에서 복사 될 때까지 기다릴 필요가 없으므로 주 스레드의 오버 헤드가 줄어 듭니다.

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*3, NULL, GL_STREAM_DRAW);
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

//write data into the mapped buffer, possibly in another thread.
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
memcpy(mappedBuffer, image, width*height*3);
SOIL_free_image(image);

// after reading is complete back on the main thread
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

그러나 PBO가 정말 빛나는 곳은 렌더링 결과를 응용 프로그램 메모리로 다시 읽어야 할 때입니다. 이 바인딩 버퍼에 픽셀 데이터를 읽어 GL_PIXEL_PACK_BUFFER 다음의 데이터 파라미터 glGetTexImage 그 버퍼에 오프셋 될 것이다 :

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, NULL, GL_STREAM_COPY);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              null);
//ensure we don't try and read data before the transfer is complete
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

// then regularly check for completion
GLint result;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(result), NULL, &result);
if(result == GL_SIGNALED){
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
    void* mappedBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);

    //now mapped buffer contains the pixel data

    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);

}

GLSL 쉐이더에서 텍스처 사용하기

버텍스 쉐이더는 텍스처 좌표를 버텍스 애트리뷰트로 받아서 프래그먼트 쉐이더에 전달합니다. 기본적으로 조각은 삼각형의 위치를 ​​기반으로 올바르게 보간 된 좌표를 받음을 보장합니다.

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoordIn;

out vec2 texCoordOut;

void main()
{
    gl_Position = vec4(position, 1.0f);
    texCoordOut = texCoordIn;
}

프래그먼트 셰이더는 texCoord 출력 변수를 입력 변수로 사용합니다. 그런 다음 uniform sampler2D 를 선언하여 프래그먼트 쉐이더에 텍스처를 추가 할 수 있습니다. 텍스처의 조각을 샘플링하기 위해 우리는 두 개의 매개 변수를 가진 내장 함수 texture 를 사용합니다. 첫 번째는 샘플링하고자하는 텍스처이고 두 번째는이 텍스처의 좌표입니다.

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

void main()
{
    color = texture(image, texCoordOut);
}

image 는 여기에 직접 텍스처 ID가 아닙니다. 샘플링 될 텍스처 유닛 의 ID입니다. 차례 차례로, 짜임새는 직접 프로그램에 묶이지 않는다; 그것들은 텍스처 유닛에 묶여있다. 이것은 glActiveTexture 텍스처 유닛을 활성화 한 다음 glBindTexture 를 호출하면이 텍스처 유닛에 영향을 미침으로써 가능합니다. 그러나 기본 텍스처 단위가 텍스처 단위 0 이기 때문에 하나의 텍스처를 사용하는 프로그램을이 호출을 생략하면 더 간단하게 만들 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow