Hello COCOBALL!

[LearnOpenGL] 23. Stencil testing 본문

OpenGL

[LearnOpenGL] 23. Stencil testing

coco_ball 2022. 8. 22. 23:04

fragment shader의 fragment 처리 후 수행되는 stencil test에서는 fragment가 폐기될지 말지 테스트 하는 단계

그 후에 depth test로 보내져서 폐기될지 말지 다시 한번 테스트 된다.

지금까지 배운 buffer와 다르게 stencil buffer라 불리는 buffer를 기반으로 수행된다.

 

stencil buffer는 일반적으로 8비트의 stencil value를 가지고 있고, pixel/fragment마다 256개의 값으로 나타내진다.

general outline

stencil testing 활성화

glEnable(GL_STENCIL_TEST);

 

color, depth buffer와 마찬가지로 매 렌더링 루프마다 stencil buffer를 비운다.

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

 

glDepthMask와 유사한 기능을 하는 함수 (buffer에 작성될 stencil 값에 AND 연산을 시킬 bitmask를 설정)

glStencilMask(0xFF); // 각 비트들은 stencil buffer 그대로 작성됩니다.
glStencilMask(0x00); // 각 비트들은 stencil buffer에 0으로 작성됩니다(작성 비활성화).

 

Stencil functions

 

stencil testing을 설정하는 두개의 함수

 

glStencilFunc(GLenum func, GLint ref, GLuint mask)

  • func: stencil test 함수를 설정합니다. 이 test 함수는 저장된 stencil 값과 glStencilFunc 함수의 ref 값에 적용됩니다. 가능한 옵션은 GL_NEVER , GL_LESS, GL_LEQUAL ,  GL_GREATER,  GL_GEQUAL, GL_EQUAL , GL_NOTEQUAL , GL_ALWAYS 가 있습니다. 이 것들의 의미는 depth buffer의 함수들과 비슷합니다.
  • ref: stencil test에 대한 레퍼런스 값을 지정합니다. stencil buffer의 내용은 이 값과 비교됩니다.
  • mask: 그들을 비교하기 전에 레퍼런스 값과 저장된 stencil 값 모두에 AND 연산이 수행되어질 mask를 지정합니다. 초기값으로는 모두 1로 설정됩니다.
glStencilFunc(GL_EQUAL, 1, 0xFF);

의미 : fragment의 stencil 값이 1과 같으면 test 통과, 그렇지 않으면 폐기

 

실제 버퍼를 수정하는 함수

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)

  • sfail: stencil test가 실패하였을 때 취할 행동
  • dpfail: stencil test가 통과했지만 depth test는 실패했을 때 취할 행동
  • dppass: stencil, depth test 모두 통과했을 때 취할 행동
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

 

Object outlining

  1. Enable stencil writing.
  2. Set the stencil op to GL_ALWAYS before drawing the (to be outlined) objects, updating the stencil buffer with 1s wherever the objects’ fragments are rendered.
  3. Render the objects.
  4. Disable stencil writing and depth testing.
  5. Scale each of the objects by a small amount.
  6. Use a different fragment shader that outputs a single (border) color.
  7. Draw the objects again, but only if their fragments’ stencil values are not equal to 1.
  8. Enable depth testing again and restore stencil func to GL_KEEP.

컨테이너를 그리면서 각 fragment의 stencil buffer 값을 1로 만들고, 컨테이너 크기를 약간 확대하여 outline을 그리는데 stencil 함수를 GL_NOTEQUAL로 설정하여 1과 같지 않은 부분만 그린다.

 

전체 과정

glEnable(GL_DEPTH_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  
  
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

glStencilMask(0x00); // 바닥을 그리는 동안에는 stencil buffer를 수정하지 않습니다
normalShader.use();
DrawFloor()  
  
glStencilFunc(GL_ALWAYS, 1, 0xFF); 
glStencilMask(0xFF); 
DrawTwoContainers();
  
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); 
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use(); 
DrawTwoScaledUpContainers();
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);

'OpenGL' 카테고리의 다른 글

[LearnOpenGL] 25. Face culling  (0) 2022.08.22
[LearnOpenGL] 24. Blending  (0) 2022.08.22
[LearnOpenGL] 22. Depth testing  (1) 2022.08.22
[LearnOpenGL] 21. Model  (0) 2022.08.22
[LearnOpenGL] 20. Mesh  (0) 2022.08.22