Face culling
큐브를 생각해보자
- 어느 방향에서 볼 수 있는 최대 면들의 개수는 3개이다.
- 다른 면들은 보이지 않는다.
- 이들을 폐기하면, 50%이상 비용을 절약할 수 있다.
문제는 view 입장에서 보이지 않는 면인지 어떻게 알 수 있는가이다.
- 닫힌 하나의 도형(closed shape)를 생각해보자
- 각 면들은 2개의 양쪽면을 가지고 있다.
- 한쪽은 사용자와 대면하고 있고, 다른 한쪽은 사용자와 등지고 있다.
Face Culling
:- viewer와 대면하고 있는 면들만 렌더링하는 것
- OpenGL은 모든 면들을 확인하여, front facing 한 면은 렌더링하고
back facing
한 모든 면들은 폐기하여 fragment shader 호출을 많이 줄여준다. (fragment shader 호출은 비용이 많이든다)- OpenGL은 이에 대해 vertex 데이터의
winding 순서
를 분석하는 똑똑한 방법을 사용한다.
Winding order
삼각형 vertex들을 정의할 때 시계방향 혹은 반시계방향으로 특정 순서를 정의한다.
- 3개의 vertex들을 삼각형의 중앙을 바라보았을 때의 winding 순서로 지정한다.
- 아래 코드가 위 이미지를 설명한다.
1 2 3 4 5 6 7 8 9 10
float vertices[] = { // clockwise vertices[0], // vertex 1 vertices[1], // vertex 2 vertices[2], // vertex 3 // counter-clockwise vertices[0], // vertex 1 vertices[2], // vertex 3 vertices[1] // vertex 2 };
- 이처럼 3개의 vertex들은 winding 순서를 가진다.
- 이 정보를 사용하여 OpenGL은
front-facing
,back-facing
인지를 결정한다.
- 이 정보를 사용하여 OpenGL은
기본값으로 반시계 방향으로 정의된 삼각형들이 front-facing 으로 처리됨
실제 winding 순서는 vertex shader가 실행되고 난 후의 rasterization 단계에서 계산된다는것.
- 그러므로 vertex들은
viewer
관점에서 보이게된다.
- 그러므로 vertex들은
viewer가 대면하고 있는 모든 삼각형 vertex들은 확실히 정확한 winding 순서로 이루어져 있다.
- 하지만 다른 면의 삼각형 vertex들은 winding 순서가 반대로 된채로 렌더링된다.(반시계 방향으로 정점을 지정했음에도 불구하고)
- 그 결과 대면하고 있는 삼각형들은 front-facing 삼각형으로 보이게 되고 뒤에 있는 삼각형들은 back-facing 삼각형으로 보이게 된다.
- 뒤에 있는 우리한테 보이지 않는 삼각형은 폐기된다.
Face culling
기본적으로 비활성화되어 있는 OpenGL의
face culling
옵션을 사용해보자반시계방향으로 winding 순서로 수정해야한다.
glEnable
GL_CULL_FACE
옵션을 활성화 시켜주자
1
glEnable(GL_CULL_FACE);
- 이 시점부터 front face 가 아닌 모든 면들은 폐기된다.
- fragment 렌더링하는데 50% 이상의 성능을 절약했다.
- 하지만 이는 큐브같은 닫힌 도형에서만 동작한다.
- blend 에서 다루었던 잔디를 그릴 때에는 face culling을 비활성화 해야한다.
- 이들은 앞, 뒤가 전부 보여야하기 때문이다.
glCullFace
- 다음 함수로 폐기하고 싶은 유형을 변경할 수 있다.
1
glCullFace(GL_FRONT);
glCullFace 함수는 3가지 가능한 옵션들을 가짐.
- GL_FRONT
- GL_BACK
- GL_FRONT_AND_BACK
기본값은 BACK
glFrontFace
- 이 함수로 face 방향을 설정할 수 있다.
1
glFrontFace(GL_CW);
기본값은 GL_CCW,
시계방향으로 변경하여 winding 순서를 반대로 해보자
1
2
3
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CW);
- 결과는 후면들만 렌더링됨
- 아래 코드는 동일한 결과를 내놓는다.
- 전면을 폐기
1
2
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
- 이처럼 face culling 은 적은 비용으로 성능을 증가시킬 수 있다.
- 어떠한 오브젝트를 face culling 해야하는지 알아야하며, 어떠한 오브젝트가 수행하면 안되는지 알아야한다(전후면 둘다 렌더링 필요할 경우).