상세 컨텐츠

본문 제목

OpenGL Stencil Buffer의 사용법

프로그래밍 관련/3D,2D DRAW 관련

by AlrepondTech 2017. 8. 18. 17:33

본문

반응형
728x170

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

OpenGL을 쓰고 항시 API를 쓰고 다시 해제해주어야 하는 API들은 해제 해주는것을 잊지 마세요 

예로들어 wglMakeCurrent(...)로 들자면 

 

HDC   hdc    = getHDC();

HGLRC hglrc = getHGLRCRES_GL();

 

::wglMakeCurrent(hdc, hglrc); //사용

 
//----------------------------------------------
//{랜더링 코드들
 
..................................................................
 
//}
//--------------------------------------------
 
::wglMakeCurrent(NULL, NULL);  //::wglMakeCurrent(hdc, NULL);  //해제

 

 

위와같이 wglMakeCurrent(...) 랜더링 부분에 Api 사용과 해제 부분을 제대로 하지 않으면 다른 

위치의 wglMakeCurrent(...) 를 사용시 문제가 생길수 있습니다.

 

 

 

 

 

=================================

=================================

=================================

 

 

 

 

출처: http://diehard98.tistory.com/m/entry/Stencil-Buffer%EC%9D%98-%EC%82%AC%EC%9A%A9%EB%B2%95

 

 

현재 내가 수행중이 프로젝트는 절묘한 Stencil Buffer 사용을 요구한다.

Framebuffer Object의 Stencil buffer를 사용하려고 하다보니 생각지 못한 문제들에 막힌적이 있었다.

우선 Framebuffer Object 사용시 Stencil Buffer의 세부 규약에 대해서 몰라서 어떻게 세팅하는지 몰랐고

다른 한가지는 Nvidia 그래픽 카드에서는 Nvidia에서만 허용되는 특수한 타입이 있는데 그것을 반드시 써야만 Framebuffer Object의 Stencil Buffer를 아무 에러없이 쓸 수 있다는 점이었다.

이것은 다음에 자세히 알아보도록 하고 오늘은 Stencil Buffer를 어떻게 정하고 또 어떻게 사용하는지만 이야기 해보자.

우선 Stencil Buffer를 정의하는 것부터 시작한다. Stencil Buffer를 어디서 정의해야 하는가 하는 의문부터 해결하자. Stencil Buffer라 함은 사용자가 원하는 부분만 그려내고 싶을때 사용하는 기술이다.

자동차 게임을 예로 들어보면 Need for speed에서 자동차 내부에서 보는 시점이 있다. 그 때에는 차 앞쪽과 측면 유리를 통해서만 외부의 세상이 보여질 뿐이다. 바로 이럴때 Stencil Buffer를 사용한다. Full Screen으로 렌더링 할 필요가 없고 사용자가 원하는 부분만 보여주고 싶을때 이다.

그렇다면 당연히 외부의 세상을 그리기 전에 Stencil Buffer를 정의해야 한다. 외부의 모든 물체를 다 그려놓고 보이지 않는 부분을 삭제하는 것과 보여지지 않는 부분을 빼고 그리는 것 둘중에 어떤것이 더 나을까 라고 스스로에게 질문해보자.

그래서 물체를 그리기 전에 다음과 같은 명령들을 내려줘야 한다.

  glColorMask(0, 0, 0, 0); // 1
  glEnable(GL_STENCIL_TEST); // 2 
  glStencilFunc(GL_ALWAYS, 1, 1); // 3 
  glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // 4
  glDisable(GL_DEPTH_TEST); // 5

  glColor3f(0.0f, 1.0f, 0.0f); // 6
  glPushMatrix(); // 7
  glTranslatef(VP_x, VP_y, -10.0f); // 8 
  glCallList(MakeMask); // 9
  glPopMatrix(); // 10
  glDisable(GL_STENCIL_TEST); // 11

1번은 Color Buffer(화면에 보여질 모습이 저장되는 버퍼)에 어떠한 색깔도 그리지 말라는 의미인데 이것을 하는 이유는 현재 우리는 Stencil Buffer에 그림을 그리고자 하는 것이지 Color Buffer에 그림을 그리고자 하는 것이 아니기 때문이다. Stencil Buffer에 그리고자 하는 그림이 화면에 그대로 보인다면 당연히 이상한 그림이 나올것이다.

2번과 5번 11번은 굳이 설명하지 않아도 알것이다. Stencil 기능을 켜고 끄며 혹은 Depth test를 끄는 기능들을 한다.

이제 3번과 4번이 중요한데 이거 상당히 복잡해서 나도 처음에 볼때는 많이 애먹었다. 3번 함수는 Stencil Buffer에 값을 쓸때 어떤 경우에 쓰고 또 어떤 값을 쓸것인가를 설정하는 함수다. 아시다시피 Stencil buffer는 단순히 생각해서 0과 1로 이루어진 bitplane이다. 즉 1이면 통과 0이면 통과 실패이다. 여기서 이해하고 넘어가야 할것은 stencil buffer를 정의할 때는 일일이 각각의 화소 위치에 대해서 1과 0을 세팅하는 것이 아니고 내가 원하는 위치에 물체를 그려 넣음으로써 그 부분은 1로 채워지게 만드는 것이다. 원래 Stencil Buffer는 모두 0으로 가득 차 있는데 내가 보여주고 싶은 부분에만 그림을 그려 넣으면 3번과 4번 함수에 의해서 그 부분의 Stencil buffer 값은 모두 1로 바뀌게 되는 것이다.

의미적으로만 설명을 했는데 3번과 4번 함수는 인터넷에서 man page를 찾아보면 금방 이해할 수 있을 것이다. 중요한 것은 이 단계에서는 Stencil buffer에 우리가 보여주고 싶은 부분만 그린다는 것이다.

6,7,8,9,10은 모두 물체를 그리는 명령이다. 다 설명하자면 너무 길고 어쨌든 줄여서 저 명령들은 내가 원하는 위치에 내가 원하는 물체를 그리는 것이다. 고로 그 위치의 Stencil Buffer 값은 모두 1로 변하게 된다. 자, 여기까지 하면 이제 비로서 Stencil Buffer를 사용할 수 있는 단계에 온것이다. 이제 고작 사용할 수 있는 단계에 온것이다. 그렇다면 어떻게 사용하느냐? 오히려 사용하는 것이 더 쉽다.

    glEnable(GL_STENCIL_TEST);
    glColorMask(1,1,1,1);
    glStencilFunc(GL_EQUAL, 1, 1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 
    glPushMatrix();
    glCallList(MakeSpaceShip);
    glPopMatrix();
 
    glDisable(GL_STENCIL_TEST);

위의 일련의 명령이 사용하는 법이다. 우선 Stencil Test를 Enable한다음 glColorMask()함수를 이용해서 지금부터 그리는 물체를 color buffer에 넣으라는 명령을 내린다. 당연히 그래야 한다. 왜? 지금부터는 사용자에게 보여줄 화면을 그리는 것이기 때문이다. 그런다음 설정함수인 glStencilFunc와 glStencilOp가 나오는데 이것은 아까 본것과 조금 다를뿐 거의 같다. 함수에 대한 설명은 여기서 다 하기 힘드니 함수 설명을 찾아보고 읽으면 금방 이해가 갈것이다. 저 두함수가 하는 역활은 들어오는 각각의 화소에 대한 값을 stencil buffer의 해당 위치의 값과 비교해서 1이면 통과 0이면 통과 실패를 시키는 것이고 추가적으로 stencil buffer에 저장되어 있는 값은 변경하지 말라는 의미이다. 당연히 stencill buffer를 변경해서는 안된다.

그리고 그 다음 좌악 나오는 명령들은 이제 진짜 그림을 그리자는 명령들이다. 

쉽게 쉽게 그리고 간단하게만 썼는데 나중에 내가 참고하려고 할때 다시 보면 이해가 잘 될지 모르겠다.ㅋㅋ
팍팍 줄여서 단계별로 설명하자면,
1. 스텐실 버퍼에 내가 보여주고자 하는 부분만 그린다.
2. 실제로 물체를 그리고자 할때에는 스텐실 버퍼 설정함수를 조작하여 스텐실 버퍼가 1의 값을 가지는 곳만 그림이 그려지도록 한다.

아주 간단하게 써보았다. :)

 

 

 

 

=================================

=================================

=================================

 

 

 

 

반응형
그리드형


관련글 더보기

댓글 영역