[TEXTURES]
1. Before
- 각 모델에는 더 많은 vertex들이, 각 vertex들은 컬러 attribute가 필요하다
: 많은 양의 overhead를 차지한다
- Texture : object에 세부 정보를 추가하는 데에 사용되는 2D image (1D, 3D도 있다)
- vertex를 추가하지 않아도 object가 매우 세밀하게 묘사된 것처럼, texture는 많은 양의 데이터를 저장하여 shader에 보낼 수 있다
2. Map to triangle
- 각 vertex가 texture의 어느 부분에 해당하는지 알려주어야한다
- 각 vertex에는 샘플링 할 texture 이미지의 영역을 지정하는 texture coordinate가 있어야한다
- fragment 보간을 통해 texture 좌표를 보간한다
3. Texture coordinate의 범위
- 범위
: x축과 y축 상의 0 ~ 1 값
: 좌측 하단 (0, 0) 부터 우측 상단 (1, 1) 까지
- sampling : texture coordinate를 사용해 texture color를 가져 오는 것
- 좌측 이미지는 texture coordinate를 삼각형에 매핑하는 이미지이다
float texCoords[] = {
0.0f, 0.0f, // lower-left corner
1.0f, 0.0f, // lower-right corner
0.5f, 1.0f // top-center corner
};
- 삼각형에 대해 3개의 좌표 포인트를 지정한다
: 삼각형의 좌측 하단이 texture의 좌측 하단과 일치하도록 삼각형의 좌측 하단 vertex에 (0, 0) texture coordinate를 사용한다
: 마찬가지로 우측 하단에도 (1, 0) texture coordinate를 사용한다
: 삼각형의 위쪽은 texture 이미지의 상단 중앙과 일치해야하므로 (0.5, 0.5) texture coordinate를 사용한다
- vertex shader에 3개의 texture coordinate를 전달하기만 하면 vertex shader는 이 좌표를 fragment shader에 전달하고, fragment shader는 모든 texture coordinate를 각 fragment에 보간한다
- texture sampling은 여러가지 방법으로 수행할 수 있으므로, OpenGL에게 texture를 sample하는 방법을 알려주어야한다
[TEXTURE WARPPING]
1. OpenGL options
- GL_REPEAT
: texture의 기본 동작으로, 이미지를 반복한다
- GL_MIRRORED_REPEAT
: GL_REPEAT와 같지만 반복할 때마다 이미지를 반대로 뒤집는다
- GL_CLAMP_TO_EDGE
: 0과 1 사이의 좌표를 고정한다.
: 가장 큰 좌표가 가장자리에 고정되어 가장자리의 패턴이 늘어나게 된다
- GL_CLAMP_TO_BORDER
: 범위 밖의 좌표에 사용자가 지정한 테두리 색이 지정된다
2. glTexParameter*
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
- 위에서 설명한 option들은 glTexParameter*함수를 사용하여 각 좌표 축을 설정할 수 있다
: 좌표 축 -> s, t, r (= x, y, z)
glTexParameter*
- 첫 번쨰 parameter : texture target을 지정한다
- 두 번째 parameter : 설정할 option과 적용하고자 하는 축을 지정한다 (위 코드에서는 WRAP 옵션을 설정하고 S축, T축 모두에 적용한다)
- 세 번째 parameter : texture wrapping mode를 설정해야하며, 이 경우에는 GL_MIRRORED_REPEAT를 사용하여 현재 활성화된 texture의 warpping option을 설정한다
float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
- GL_CLAMP_TO_BORDER option을 선택하면 테두리의 색도 설정해야한다
: fv를 사용하는 glTexParameter 함수를 호출하여, parameter로 GL_TEXTURE_BORDER_COLOR option을 넣어 수행할 수 있다
: 이 option은 테두리의 color 값을 float 배열로 전달한다
[TEXTURE FILTERING]
1. GL_NEAREST, GL_LINEAR
- texture coordinate는 해상도에 의존하지 않지만 float 값이 될 수 있으므로 OpenGL은 texture coordinate를 mapping할 texture pixel(texel)을 찾아야한다
: 매우 큰 object와 낮은 해상도 texture를 가진 경우, 특히 더 중요하게 작용한다
: OpenGL에는 이러한 기능을 위한 다양한 texture filtering option이 존재한다
(지금은 가장 중요한 option인 GL_NEAREST와 GL_LINEAR에 대해서만 설명한다)
GL_NEAREST (nearset neighbor filtering)
- OpenGL의 기본적인 texture filtering 방법이다
- texel의 중심이 texture coordinate에 가장 가까운 texel을 선택한다
- 좌측의 이미지에서, 4개의 pixel에서 십자가는 정확한 texture coordinate를 나타낸다
: 이미지에서 좌측 상단 texel의 중심이 texture coordinate와 가장 가까우므로 샘플링된
색상으로 선택되어 return된다
GL_LINEAR ((bi)linear filtering)
- texture coordinate의 이웃한 texel에서 보간된 값을 가져와 texel 사이의 색상의 근사치를
가져온다
- texture coordinate에서 texel 중심까지의 거리가 가까울 수록 해당 texel의 색상이 샘플링 된 색상에 더 많이 혼합된다
: 좌측 이미지에서 인접한 pixel의 색상이 혼합된 샘플링 색상이 return됨을 확인할 수 있다
- GL_NEAREST VS GL_LINEAR
: 큰 object에 해상도가 낮은 texture를 사용할 때, texture의 크기가 확장되고 개별 texel들이 눈에 띈다
NEAREST
: texture를 형성하는 pixel들을 명확히 볼 수 있는 차단된 패턴을 생성한다 (blocked pattern)
: 8bit look
LINEAR
: 개별 pixel들이 덜 보이는 더 매끄러운 패턴을 생성한다 (smoother pattern)
: NEAREST보다 더 현실감 있는 결과를 산출한다
- 확대(Magnifying) 및 축소(Minifying) 작업 설정 (scale up or scale down)
: texture가 축소될 때는 NEAREST를 사용하고, 확대될 때는 LINEAR를 사용한다
: glTexParameter*를 통해 두 option에 대한 필터링 방법을 지정해야한다 (코드는 wrapping 방법을 설정하는 것과 유사하다)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2. Mipmaps
- 넓은 공간에 각각 texture가 첨부된 수천 개의 object가 있을 경우, object가 시점에서 멀리 떨어질 수록 fragment를 적게 생성하기 때문에 OpenGL은 고해상도 texture에서 해당 fragment의 올바른 색상 값을 가져오는 데에 어려움을 겪는다. 이것은 작은 object에 고해상도 texture를 사용하여 메모리 낭비와 작은 object의 결함이 보이는 문제를 야기한다.
: 이를 해결하기 위해 OpenGL은 기본적으로 mipmaps 개념을 사용한다
- mipmaps
: 이전 texture보다 2배 작은 texture image를 다음 texture로 가지는 texture 집합이다
: 시점에서 특정 거리의 임계 값을 넘으면 object까지의 거리에 가장 적합한
mipmap texture를 사용한다
: 물체가 멀리 떨어져 있으므로 작은 해상도의 texture는 사용자의 눈에 잘 띄지 않는다
: mipmap은 작은 캐시 메모리를 사용하므로 성능 향상에 도움이 된다
: glGenerateMipmap 함수를 호출하여 모든 작업을 수행할 수 있다
- 렌더링 중 mipmap의 level을 전환할 때 두 mipmap 레이어 사이에 가장자리가 선명히 나타나는 것과 같은 일부 결함이 생길 수 있다
- 일반적인 texture filtering과 마찬가지로 mipmap level을 전환하기 위해 NEAREST 및 LINEAR filtering을 사용하여 mipmap level 사이를 filtering 할 수 있다
- mipmap level 사이의 필터링 방법을 지정하기 위해 원래의 필터링 방법을 아래의 네 가지 option 중 하나로 대체할 수 있다
GL_NEAREST_MIPMAP_NEAREST
: nearest neighbor 보간법으로 mipmap을 필터링하고 텍스처 샘플링도 nearest neighbor 보간법을 사용한다
GL_LINEAR_MIPMAP_NEAREST
: nearest neighbor 보간법으로 mipmap을 필터링하고 텍스처 샘플링은 linear 보간법을 사용한다
GL_NEAREST_MIPMAP_LINEAR
: linear 보간법으로 mipmap을 필터링하고 텍스처 샘플링은 nearest neighbor 보간법을 사용한다
GL_LINEAR_MIPMAP_LINEAR
: linear 보간법으로 mipmap을 필터링하고 텍스처 샘플링도 linear 보간법을 사용한다
- texture filtering과 마찬가지로 glTexParameteri 함수를 사용하여 필터링 방법을 설정할 수 있다
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
: mipmap은 texture가 축소될 때 주로 사용되므로 필터링 option 중 하나를 확대 필터로 설정하는 것은 아무런 효과가 없다
: texture 확대에서는 mipmap을 사용하지 않으며, option을 지정하면 GL_INVALID_ENUM 오류 코드를 생성한다
[LOADING AND CREATING TEXTURES]
1. stb_image.h
- 가장 많이 쓰이는 파일 형식을 로드할 수 있고 프로젝트에 쉽게 통합할 수 있는 single header image loading library이다
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
- STB_IMAGE_IMPLEMENTATION을 정의함으로써 perprocessor(전처리기)는 header file을 관련된 정의 source code만 포함하도록 한다
: header file을 효과적으로 .cpp file로 변환한다
int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
- stbi_load 함수를 사용하여 이미지를 로드한다
첫 번째 parameter : 이미지 파일의 경로를 설정한다
두 번째 parameter : 결과 이미지로부터 받아올 너비 값을 저장할 int형 변수를 지정한다
세 번째 parameter : 결과 이미지로부터 받아올 높이 값을 저장할 int형 변수를 지정한다
네 번째 parameter : 결과 이미지로부터 받아올 컬러 채널의 수 값을 저장할 int형 변수를 지정한다
다섯 번째 parameter
: 결과 이미지를 로드할 때 사용하기를 원하는 컬러 채널 값을 지정한다
: 값을 0으로 지정하면 이미지를 그대로 로드하며, 이외에는 nrChannels의 값을 사용하여 지정한다 (Ex) 1로 지정하면 흑백으로 로드된다)
- nrChannels 변수에는 4가지 경우에 따라 1~4 사이의 값을 가진다
01] nrChannels = 1 : 흑백
02] nrChannels = 2 : 흑백 + alpha
03] nrChannels = 3 : RGB컬러
04] nrChannels = 4 : RGB컬러 + alpha
- 오류가 발생하면 NULL을 return 한다
2. Generating a Texture
unsigned int texture;
glGenTextures(1, &texture)
- 이전의 object들과 마찬가지로 texture는 ID로 참조된다
glGenTextures (생성할 texture의 개수, unsigned int array)
: 두 번째 parameter로 주어진 unsigned int array에 texture를 저장한다
glBindTexture(GL_TEXTURE_2D, texture);
- texture를 바인딩 하여 texture 명령이 현재 바인딩 된 texture를 대상으로 설정할 수 있도록 한다
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
- glTexImage2D 함수를 이용하여 texture를 생성한다
: 한 번 호출하면 현재 바인딩된 texture object가 첨부된 texture image를 가진다
: mipmap을 사용하려면 모든 이미지들을 계속해서 2번째 parameter를 증가시키는 형식으로 직접 지정하거나 texture를 생성한 후 glGenerateMipmap 함수를 사용해야한다 (이 함수는 현재 바인딩된 texture에 대해 필요한 모든 mipmap을 자동으로 생성한다)
glTexImage2D
첫 번째 parameter
: texture target을 지정한다
: GL_TEXTURE_2D로 설정하는 것은 현재 GL_TEXTURE_2D로 바인딩된 texture object에 texture를 생성하겠다는 것을 뜻한다
(따라서 이 경우, GL_TEXTURE_1D나 GL_TEXTURE_3D로 바인딩된 object에는 아무런 영향을 끼치지 않는다)
: 사용 가능한 입력으로는GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_POSITIVE_X 등이 있다
두 번째 parameter
: 생성하는 texture의 mipmap level을 수동으로 지정하고 싶을 때 지정한다
: base level은 0이며, n 레벨은 n번째 mipmap 이미지를 뜻한다
세 번째 parameter
: texture의 컬러 구성요소 수를 지정한다
: 1 ~ 4 사이의 정수 값 또는 정해져있는 기호 상수를 사용하여 지정한다
: 사용 가능한 입력으로는 GL_RGB, GL_ALPHA, GL_COMPRESSED_RGBA, GL_LUMINANCE, GL_SRGB 등이 있다
(현재 사용할 이미지는 오직 RGB 값만 가지므로 GL_RGB로 지정하여 사용한다)
네 번째, 다섯 번째 parameter
: 결과 texture의 width와 height를 설정한다
: stbi_load를 통해 이미지를 로드할 때 이미 저장해두었으므로 해당 변수를 그대로 사용했다
여섯 번째 parameter
: 이미지 테두리의 너비를 지정한다 (0 또는 1)
: 교재에서는 항상 0이어야한다고 하지만 1을 사용하는 경우도 있는 것 같다
일곱 번째 parameter
: 원본 이미지의 format(pixel data type)을 지정한다
: 사용 가능한 입력으로는 GL_COLOR_INDEX, GL_ALPHA, GL_RGB 등이 있다
: 지금은 RGB 값이 있는 이미지를 로드했으므로 GL_RGB로 지정했다
여덟 번째 parameter
: 원본 이미지 pixel data의 data type을 지정한다
: 사용 가능한 입력으로는 GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT_2_10_10_10_REV 등이 있다
: 지금은 이미지를 chars(bytes)로 저장하였으므로 GL_UNSIGNED_BYTE로 지정했다
아홉 번째 parameter
: 메모리에 있는 실제 image data에 대한 포인터를 지정한다
: 지금은 data에 이미지를 로드 했으므로 data로 지정했다
glGenerateMipmap
: texture object가 glGenerateMipmap에 바인딩될 대상을 지정한다
: 사용 가능한 입력으로는GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_1D_ARRAY, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY가 있다
stbi_image_free(data);
- texture와 해당 mipmap을 모두 생성한 후 이미지의 메모리를 반환한다
// texture 생성의 전체적인 과정
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// set the texture wrapping/filtering options (on the currently bound texture object)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load and generate the texture
int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
3. Applying Textures
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
- 이전 Hello Triangle 파트에서 그렸던 사각형을 사용한다
: OpenGL에게 texture를 샘플 하는 방법을 알려주어야 하므로, texture coordinate를 vertex data에 추가한다
- vertex attribute를 추가했기 때문에 OpenGL에게
새로운 vertex format을 다시 알려주어야한다
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
- 이전의 2개의 vertex attribute가 있었을 때의 stride parameter를 8*sizeof(float)로 수정해야한다
// Vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
- vertex attribute로서 texture coordinate를 받을 수 있도록 vertex shader를 수정해야한다
: 이 과정에서 texture coordinate는 fragment shader로 넘어간다
// Fragment shader
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord);
}
- fragment shader는 TexCoord 출력 변수를 입력 변수로서 받게 된다
- fragment shader는 texture object에 접근할 수 있어야한다
: sampler texture object type을 사용한다 (sampler 1D, sampler 2D, sampler 3D가 있고 지금은 sampler 2D를 사용한다)
: texture를 집어넣을 uniform sampler 2D를 선언하기만 하면 texture를 fragment shader에 전달할 수 있다
- texture color를 샘플링하기 위해 GLSL의 texture 함수를 사용한다
texture(texture smapler, texture coordinate)
: texture 함수는 앞서 설정했던 texture parameter를 사용하여 해당 컬러 값을 샘플링한다
: fragment shader의 출력은 보간된 texture coordinate에서 필터링 된 texture의 색상이다
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
- glDrawElements 함수를 호출하기 전에 texture를 바인딩해야한다
: texture를 fragment shader의 sampler로 자동 할당하게 된다
FragColor = texture(ourTexture, TexCoord) * vec4(ourColor, 1.0);
- 최종 texture color와 vertex color를 곱하여 두 컬러를 혼합할 수 있다
- 위의 모든 과정을 실행했을 때 볼 수 있는 결과 화면이다
4. Texture Units
- glUniform1i 함수를 사용하여 실제로 texture sampler에 위치 값을 할당하여 fragment shader에서 동시에 여러 texture를 설정할 수 있다
: 이 texture의 위치는 texture unit으로 알려져있다
- 기본 texture unit은 0이다
: 기본으로 활성화된 texture unit이므로 이전의 섹션에서는 위치 값을 할당할 필요가 없었다
- texture unit의 주 목적은 shader에서 하나 이상의 texture를 사용할 수 있도록 하는 것이다
: sampler에 texture unit을 할당함으로써 해당 texture unit을 활성화하기만 하면 여러 texture들을 동시에 바인딩할 수 있다
glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, texture);
- glBindTexture 함수와 마찬가지로 glActiveTexture 함수에 texture unit을 전달하여 호출함으로써 texture unit을 활성화할 수 있다
: GL_TEXTURE0는 항상 기본으로 활성화되므로 이전에 glBindTexture 함수를 사용할 때 어떠한 texture unit도 활성화하지 않아도 되었다
- texture unit을 활성화한 후에 호출되는 glBindTexture 함수는 현재 활성화된 texture unit에 바인딩한다
- OpenGL은 최소 16개의 texture unit을 가지고 있어, GL_TEXTURE0 ~ GL_TEXTURE15까지 사용할 수 있다
: 이들은 순서대로 선언되어 있어, GL_TEXTURE8에 접근할 때 GL_TEXTURE+8과 같은 형식으로도 접근 할 수 있다
#version 330 core
...
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
- 다른 sampler를 받기 위해 fragment shader를 수정한다
: 최종 출력 걸러는 두 개의 texture를 혼합한 것이다
- GLSL의 mix 함수는 입력으로 두 개의 값을 받고, 세 번째 parameter를 기반으로 LINEAR 보간법을 통해 값을 보간한다
: 세 번째 parameter
= 0.0이면, 첫 번째 texture return
= 1.0이면, 두 번째 texture return
= 0.2이면, 첫 번째 texture 80% 두 번째 texture 20% return
unsigned char *data = stbi_load("awesomeface.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
- 새로운 texture object를 생성하고 이미지를 로드한 후, glTexImage2D 함수를 사용해 최종 texture를 생성하는 코드이다
- alpha channel을 가지고 있는 .png 이미지를 로드한다
: GL_RGBA를 사용하여 alpha channel을 포함하고 있는 이미지 데이터임을 명시해야한다
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
- 두 개의 texture를 해당 texture unit에 모두 바인딩해야한다
- 여러 개의 texture unit을 바인딩해야하므로 render loop 속 bind texture 부분에서 약간의 코드 수정이 필요하다
: 이전 코드에서 bind texture 부분은 glBindTexture(GL_TEXTURE_2D, texture) 코드 한 줄이 끝이었지만, 이번 코드에서는 glActiveTexture 함수를 사용하여 여러 개의 texture unit을 활성화한다
ourShader.use(); // don't forget to activate the shader before setting uniforms!
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0); // set it manually
ourShader.setInt("texture2", 1); // or with shader class
while(...)
{
[...]
}
- glUniform1i 함수를 사용하여 각 sampler를 설정함으로써 OpenGL에게 각 shader sampler가 속하는 texture unit이 어떤 것인지를 알려주어야한다
: 이를 설정하는 것을 통해 각 uniform sampler를 적절한 texture unit과 맞출 수 있다
- 한 번만 설정하면 되기 때문에 render loop 전에 실행한다
stbi_set_flip_vertically_on_load(true);
- 위 코드를 추가하지 않고 실행한다면 texture가 거꾸로 뒤집혀서 출력된다
: 대부분의 이미지는 y축의 0.0 좌표를 이미지의 위쪽을 가리키지만, OpenGL은 y축의 0.0 좌표를 이미지의 아래쪽으로 인식하기 때문이다
: 따라서 위 코드를 추가함으로써 이미지를 정상적으로 출력할 수 있다
- 전체적인 코드를 실행했을 때 출력되는 결과 이미지이다
'OpenGL Study' 카테고리의 다른 글
OpenGL "Materials" (2) | 2023.01.12 |
---|---|
OpenGL "Colors" (0) | 2023.01.06 |
OpenGL "Camera" (0) | 2022.12.06 |
OpenGL "Coordinate Systems" (1) | 2022.11.30 |
OpenGL "Transformations" (1) | 2022.11.22 |