눈팅하는 게임개발자 블로그
OpenGL Advanced 5-4 Face culling 본문
원문 사이트
learnopengl.com/Advanced-OpenGL/Face-culling
번역 사이트
heinleinsgame.tistory.com/27?category=757483
Face culling
마음속으로 3D 큐브를 상상해보고 어느 방향에서든 해당 큐브의 면은 최대 3개까지 볼 수 있을 것이다.
어떠한 위치나 방향에서든 큐브를 볼 수 있지만 3개보다 많은 면들을 보는 것은 불가능하다.
그렇다면 3개의 면이 아닌 볼 수 없는 다른 3개의 면은 렌더링을 할 필요가 없다는 것을 알 수 있는데,
이들을 특정 방법으로 폐기한다면 fragment shader의 비용을 50% 이상 절감할 수 있다.
특정 각도에서는 오직 2개 또는 1개의 면만 볼 수 있기 때문에 50%만이 아닌 50% 이상이 절약된다고 할 수 있다. |
이는 훌륭한 아이디어이다. 하지만 해결해야 할 문제가 존재한다.
이 면이 Viewer(카메라)의 입장에서 보이는 면인지 아닌지 판별해야 한다.
닫힌 도형을 상상해보면 각 면들은 2개의 양쪽 면을 가지고 있다.
한쪽은 사용자와 대면하고 있고 다른 한쪽은 사용자와 등지고 있다.
여기서 viewer와 대면하고 있는 면들만 렌더링 할 수 있도록 하는 것이 face culling이 하는 일이다.
OpenGL은 모든 면들을 확인하여 viewer의 관점에서 front facing한 면은 렌더링하고
back facing한 모든 면들은 폐기하여 fragment shader 호출(비용이 많이 든다.)을 많이 줄여준다.
이를 위해 OpenGL에게 현재 씬에 사용되는 면들이 실제로 앞쪽 면인지 뒷쪽 면인지 알려줄 필요가 있다.
OpenGL은 이에 대해 vertex 데이터의 winding 순서를 분석하는 똑똑한 방법을 사용한다.
Winding Order
삼각형 vertex들을 정의할 때 시계 방향 혹은 반시계 방향으로 특정 순서를 정의한다.
각 삼각형은 3개의 vertex를 가지고 있고 이 3개의 vertex들을 삼각형의 중앙을 바라보았을 때의
winding 순서로 지정한다.
이미지에서 확인할 수 있듯이 먼저 vertex1을 정의한 후 vertex 2나 3을 정의할 수 있다.
이 선택은 삼각형의 winding 순서를 정의한다.
이는 다음 코드와 같다.
float vertices[] = {
// 시계 방향
vertices[0], // vertex 1
vertices[1], // vertex 2
vertices[2], // vertex 3
// 반시계 방향
vertices[0], // vertex 1
vertices[2], // vertex 3
vertices[1] // vertex 2
};
각 삼각형을 이루고 있는 3개의 vertex들은 winding 순서를 가지고 있다.
OpenGL은 렌더링할 때 이 정보를 사용하여 삼각형이 front-facing인지 back-facing인지를 결정한다.
기본 값으로는 반시계 방향으로 정의된 삼각형들이 front-facing 삼각형으로 처리된다.
vertex 순서를 정의할 때 해당 삼각형이 viewer를 대면하고 있는지를 상상해보자.
그리고 현재 지정하고 있는 삼각형이 반시계 방향이어야 한다.
모든 vertex들을 이처럼 지정하면 winding 순서가 vertex shader가 실행된 이후의 rasterization 단계에서
계산된다는 것에서 이점을 가진다.
다음 vertex들은 viewer의 관점에서 보이게 된다.
viewer가 대면하고 있는 모든 삼각형 vertex들은 확실히 정확한 winding 순서로 이루어져 있다.
하지만 큐브의 다른 면의 삼각형 vertex들은 winding 순서가 반대로 된채로 렌더링된다.
그 결과 대면하고 있는 삼각형들은 front-facing 삼각형으로 보이게 되고
뒤에 있는 삼각형들은 back-facing 삼각형으로 보이게 된다.
다음 이미지가 이 효과를 보여준다.
vertex 데이터에서 두 삼각형을 viewer의 시점에서 반시계 방향으로 정의했을 것이다.
하지만 viewer의 방향으로부터 뒤에 있는 삼각형은 시계 방향으로 렌더링된다.
뒤에 있는 삼각형도 반시계 방향으로 지정하였음에도 불구하고 시계 방향으로 렌더링된다.
이는 viewer의 시점에서 보이지 않는 면들을 폐기하기 위해 판별할 때 사용될 수 있다.
Face culling
이 강좌의 처음에 OpenGL이 등지고 있는 삼각형들을 폐기할 수 있다고 언급했다.
이제 vertex들의 winding 순서를 설정하는 방법을 알았으므로 기본적으로 비활성화되어 있는 OpenGL의
face culling 옵션을 사용할 수 있다.
지난 강좌들에서 사용했던 큐브의 vertex 데이터는 반시계 방향의 winding 순서로 정의되지 않았었다.
그래서 반시계 방향으로 winding 순서로 수정해야 한다.
이 vertex들이 모두 정확히 반시계 방향으로 정의되어 있다는 것을 유념해야 한다.
face culling을 활성화하기 위해 OpenGL의 GL_CULL_FACE 옵션을 활성화시키기만 하면 된다.
glEnable(GL_CULL_FACE);
이 시점부터 앞쪽 면이 아닌 모든 면들은 폐기된다.(큐브의 내부로 들어가면 내부에 있는 면들이 정확히 폐기되었음을 확인할 수 있다.)
현재 fragment를 렌더링 하는 데에 50% 이상의 성능을 절약했다.
하지만 이는 오직 큐브처럼 닫힌 도형에서만 동작한다는 것을 유념해야 한다.
이전 강좌의 잔디를 그릴 때에는 face culling을 비활성화해야 한다.
이들은 앞쪽면과 뒷쪽면이 모두 보여야 하기 때문이다.
OpenGL은 폐기하려는 면의 유형을 바꿀수 있도록 해준다.
후면이 아니라 전면을 폐기하고 싶다면 glCullFace 함수를 통해 이를 지시할 수 있다.
glCullFace(GL_FRONT);
glCullFace 함수는 3개의 옵션들을 가지고 있다.
GL_BACK : 후면만을 폐기한다.
GL_FRONT : 전면만을 폐기한다.
GL_FRONT_AND_BACK : 전면, 후면 모두 폐기한다.
glCullFace 함수의 기본 값은 GL_BACK이다.
폐기한 면 뿐만 아니라 OpenGL에게 시계 방향의 면들이 후면이 아니라 전면이라고 알려줄 수도 있다.
glFrontFace함수를 사용한다.
glFrontFace(GL_CCW);
기본 값은 GL_CCW이므로 반시계 방향을 나타낸다.
다른 옵션은 GL_CW으로 시계 방향을 나타낸다.
간단한 실험으로서 OpenGL에게 이제 전면은 반시계 방향이 아니라 시계 방향이라고 말해줌으로써 winding 순서를
반대로 할 수 있다.
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
결과는 후면들만 렌더링된다.
반시계 방향의 winding 순서로 유지하고 전면을 폐기함으로써 동일한 효과를 얻을 수도 있다.
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
보다시피 face culling은 적은 비용으로 OpenGL 응용 프로그램의 성능을 증가시킬 수 있는 좋은 도구이다.
어떤 오브젝트가 face culling의 이점을 누릴 수 있고 어떤 오브젝트가 face culling을 하면 안되는지 알고 있어야 한다.
'공부한거 > OpenGL' 카테고리의 다른 글
OpenGL Advanced 5-7 Advanced Data (0) | 2020.12.10 |
---|---|
OpenGL Advanced 5-5 Framebuffers (0) | 2020.12.10 |
OpenGL Advanced 5-3 Blending (0) | 2020.12.09 |
OpenGL Advanced 5-2 Stencil testing (0) | 2020.12.08 |
OpenGL Advanced 5-1 Depth testing (0) | 2020.12.08 |