Post Lists

2018년 7월 30일 월요일

Advance OpenGL - Face culling (4)

https://learnopengl.com/Advanced-OpenGL/Face-culling

Face culling
시각적으로 3D 정육면체를 시각화하려고 하고, 너가 어떤 방향으로부터 볼 수 있을 면들의 최대 개수를 세어라. 만약 너의 상상이 너무 창의적이지 않다면, 너는 아마도 최대 3개로 끝나게 된다. 너는 어떤 위치 어떤 방향으로든 한 정육면체를 볼 수 있지만, 너는 결코 3면 이상을 볼 수가 없을 것이다. 그래서 왜 우리는 실제로 우리가 심지어 볼 수 없는 그 다른 3개의 면들을 그리는 노력을 낭비하는 것인가? 만약 우리가 어떤 방식으로 그러한 것들을 버린다면, 우리는 fragment shader의 50% 이상 작동하는 것을 절약할 수 있다.

  Green Box
  우리는 50% 대신에 50% 이상이라고 말한다. 어떤 각도로 부터, 오직 2개 또는 심지어 1개의 면만이 보일 수 있기 때문이다. 그러한 경우에 우리는 50% 이상을 절약한다.

이것은 정말 훌륭한 아이디어 지만, 우리가 해결해야 할 한 문제가 있따: 어떻게 우리는 한 오브젝트의 한 면이 그 viewer의 관점으로부터 보이지 않는치를 알 것인가?
만약 우리가 어떤 closed shape를 상상한다면, 그것의 면들 각각은 두 면을 가진다. 각 면은 사용자를 바라보거나 또는 사용자에게 그것의 뒤를 보여줄 것이다. 우리가 오직 viewer를 바라보는 면만을 렌더링하면 어떨까?

이것은 정확히 face culling이 하는 것이다. OpenGL은 viewer 쪽으로 바라보는 앞에 있는 면들을 체크하고, 그러한 것들을 렌더링한다. 반면에 뒤로 향하는 모든 면들을 버린다. 이것은 우리에게 많은 fragment shader calls들을 절약해준다 (그것들은 비싸다!). 우리는 OpenGL에게 우리가 우리가 사용하는 어떤 면들이 실제로 앞면이고 뒷 면인지를 말할 필요가 있다. OpenGL은 이것을 위해 vertex data의 winding order(감기는 방향)을 분석하여 똑똑한 트릭을 사용한다.

Winding order
우리가 삼각형의 정점들의 한 세트를 정의할 때, 우리는 시계방향 또는 반시계방향 둘 중 하나로 그것들을 어떤 감기는 방향으로 정의한다. 각 삼각형은 3개의 정점들로 구성되고, 우리는 삼각형의 중심으로부터 보이듯이 감기는 순서대로 그러한 3개의 정점들을 명시한다.

너가 이미지에서 볼 수 있듯이, 우리는 처음에 vertex 1을 정의하고, 그러고나서 우리는 vertex 2또는 3을 정의한다. 이 선택은 이 삼각형의 감기는 순서를 정의한다. 다음의 코드는 이것을 보여준다:


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
};

삼각형 primitive를 형성하는 3개의 정점들의 각 세트는 따라서 감기는 순서를 포함한다. OpenGL은 너의 프리미티브를 렌더링 할 때, 한 삼각향이 앞을 바라보는 지 또는 뒤를 바라보는 삼각형인지를 결정하기 위해 이 정보를 사용한다. 기본적으로 시계 반대 방향으로 정의된 삼각형들은 앞면을 바라보는 삼각형들로 처리 된다.

너의 정점 순서를 정의할 때, 너는 마치 그것이 너를 바라보는 것처럼 그에 상응하는 삼각형을 시각화 한다. 그래서 너가 명시하는 각 삼각형은 마치 너가 직접적으로 그 삼각형을 바라보는 것처럼. 시계 반대방향 이여야 한다. 모든 너의 정점들을 이렇게 정의하는 것에 대해 좋은 점은 실제 winding order가 rasterization stage에서 계산된다는 것이다. 그래서 vertex shader가 이미 작동했을 때, 그 정점들은 그러고나서 그 viewer의 관점으로부터 보여진다.

그 viewer가 그러고나서 바라보고있는 모든 삼각형 정점들은 우리가 그것들을 명시했 듯이 올바른 winding order에 있지만, 그 정육면체의 다른 면에 있는 삼각형의 정점들은 이제 그것들의 winding order가 역이 된 방식으로 렌더링 되어진다. 그 결과는, 우리가 바라보는 삼각형들은 앞에서 보는 삼각형처럼 보여지고, 뒤에 있는 삼각형들은 뒤에서 바라보는 삼각형이 된다. 다음의 이미지는 이 효과를 보여준다:

vertex data에서 우리는 시계 반대 방향으로 두 삼각형을 정의해왔다. 그러나, viewer의 방향으로 부터, 뒤에 있는 삼각형은 시계 방향으로 렌더링 되어진다. 만약 우리가 그것을 viewer의 현재 관점으로부터 1,2,3으로  그려야 한다면. 비록 우리가 back triangle을 시계 반대 방향으로 명시했었을 지라도, 그것은 이제 시계 방향을 렌더링 되어진다. 이것은 정확히 우리가 보이지 않는 면을 cull(버리기) 원하는 방식이다.

Face culling
튜토리얼의 시작에서, 우리는 OpenGL이 그것들이 뒤를 바라보고 있는 삼각형으로서 렌더링 되어야 한다면 삼각형 프리미티브들을 버릴 수 있다고 말했었다. 우리는 어떻게 정점들의 감기는 순서를 설정할지를 알았으니, 기본적으로 비활성화된 OpenGL의 face culling option을 사용하기 시작할 수 있다.

우리가 지난 튜토리얼에서 사용했던 cube vertex data는 시계 반대 방향의 감기는 순서로 정의되지 않았다. 그래서 나는 너가 여기에서 복사할 수 있도록 시계 반대 방향의 감기는 순서를 반영하는 vertex data를 업데이트 했다. 이러한 정점을 각 삼각형에 대해 시계 반대방향으로 모두 정의된 것을 시각화하고 시도해보는 것은 좋은 연습이다.

face culling을 활성화하기 위해, 우리는 오직 OpenGL의 GL_CULL_FACE 옵션을 활성화 해야만 한다:

  glEnable(GL_CULL_FACE);

이 시점부터, 앞면이 아닌 모든 면들은 버려진다. (정육면체의 내부로 날아들어가, 모든 내부 면들이 정말로 버려지는지 보아라). 현재 우리는 fragments를 렌더링하는 성능의 50% 이상으 ㄹ아끼지만,  이곳이 cube 처럼 오직 닫혀진 shapes와만 작동하는 것을 주목해라. 우리는 이전 튜토리얼의 예 처럼 grass leaves를 그릴 때, face culling을 다시 꺼야만 할지도 모른다. 그것들의 앞과 뒷면은 보여야 하기 때문이다.

OpenGL은 또한 우리가 cull하기 원하는 면의 타입을 바꾸도록 해준다. 우리가 앞면을 cull하기 뒷면을 하지 않고싶다면 어떨까? 우리는 이 행동을 glCullFace를 호출하여 정의할 수 있다:

  glCullFace(GL_FRONT);

glCullFace 함수는 세 가지 가능한 옵션들을 갖는다:


  • GL_BACK : 뒷 면만을 깍는다.
  • GL_FRONT : 앞 면만을 깍는다.
  • GL_FRONT_AND_BACK : 앞 뒷 면을 깍는다.
glCullface의 초기값은 GL_BACK이다. 깍을 면들을 제외하고, 우리는 OpenGL에게 우리가 오히려 반시계방향 대신에 앞면으로서 시계 방향의 면을 선호한다고 말할 수 있다. glFrontFace를 통해 :

  glFrontFace(GL_CCW);

그 기본값은 GL_CCW이고, 이것은 반 시계 순서를 상징한다. 다른 옵션이 GL_CW가 되게하고. 그 GL_CW는 (명백히) 시계 방향 순서를 상징한다.

간단한 테스트로서, 우리는 OpenGL에게 앞면들을 이제 반 시계 순서 대신에 시계 순서로 결정되어야 한다고 말하여서 감기는 순서를 역전시킬 수 있다:

  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);
  glFrontFace(GL_CW);

그 결과는 오직 뒷 면들 만이 렌더링 된다:


기본 반시계 감는 순서로 앞면을 깍아서 같은 효과를 만들 수 있다는 것을 알아둬라:

  glEnable(GL_CULL_FACE);
  glCullFace(GL_FRONT);

너도 볼 수 있듯이, face culling은 너의 OpenGL 프로그램들의 성능을 적은 노력으로 향상시키기 위한 훌륭한 도구이다. 너는 어떤 오브젝트들이 실제로 face culling으로부터 이익을 얻는지와 어떤 오브젝트들이 culled 되어선 안되는지를 추적해야만 한다.

Exercises
  • 너는 각 삼각형을 시계방향 순서로 명시하여 정점 데이터를 재정의하고 clockwise triangles을 front face로하여 scene을  렌더링 할 수 있는가? 
vertices를 일일이 다 하는 것은 귀찮은 일이다. 그러므로,
정육면체의 6개의 점을 정의하고, EBO를 통해 Elements를 clockwise로 한다.
그리고나서, glFrontFace(GL_CW)로 바꾼다.

댓글 없음:

댓글 쓰기