[프로그램] 스텐실 버퍼 (Stencil Buffer)
스텐실 버퍼 (Stencil)
스텐실 버퍼는 렌더링시 픽셀이 써질지 안 써질지 결정하게 해줌.
일단 스텐실 버퍼를 사용하려면 버퍼를 만들때 스텐실에 비트를 할당해야 하는데 보통 D3DFMT_D24S8 로 요청한다 . Depth (z깊이버퍼) 에 24 비트 , Stencil 에 8 비트를 할당한다.
이렇게 하면 표면 픽셀 하나마다 깊이 값 24 비트, 스텐실 값 8 비트까지 사용하면서 처리할 수있다.
| Z 버퍼
일단 z 버퍼에서는 z 값을 비교해서 픽셀을 쓸지 안쓸지 결정한다 . 어떤 픽셀을 렌더했는데그 픽셀이 버퍼의 [3][3] 자리의 픽셀에 써져야 한다고 치자 . 픽셀을 쓰기전 그 새로 써지려는픽셀의 z 값과 새로 써지려는 이 픽셀의 버퍼 상의 픽셀 자리 [3][3] 번째의 z 값을 비교한다.
비교해서 버퍼 상의 z 값이 더 크면 새로 써지려는 픽셀이 가깝다는 의미가 되므로 색상 버퍼에 그 z 테스트를 통과한 픽셀의 색상이 써지고 써진 그 픽셀의 자리([3][3] 가정) 의 z 값이 새로운 z 값 , 즉 z 테스트를 통과한 픽셀의 z 값으로 교체된다 . 이렇게 앞뒤를 구분해서 렌더링해주는게 Z 버퍼의 기능이다.
스텐실 버퍼도 Z 버퍼 처럼 테스트를 해서 픽셀을 쓸지 안쓸지를 결정해주는 버퍼이다.
Z 버퍼에선 새로 써지는 픽셀의 Z 값이 더 가까우면 픽셀을 썼지만 스텐실 버퍼에선 대부분을 사용자가 컨트롤한다 . 무슨 의미냐면 Z 버퍼에선 픽셀의 Z 값이 버퍼 상의 Z 값보다 작아야 픽셀이 등록되지만 스텐실 버퍼에선 사용자가 정한 값 (참조값이라함) 써지는 픽셀의 버퍼상에서 매치되는 자리의 스텐실 값보다 작던지 크던지 같던지 옵션을 정해서 픽셀을 쓸지 안쓸지 결정할수있다.
즉 Z 버퍼에선 픽셀을 쓰려할때마다 그 픽셀의 Z 값이 다 따로 있지만 스텐실 버퍼는 참조값이라 해가지고 사용자가 값을 하나 정하고, 비교하는 방식 을 정한후(비교 함수라함)
현재의 스텐실 참조값과 새로 써지는 픽셀의 자리 ( 여기서 [3][3] 이라 가정하겠음 ) 와 사용자가 지정한 비교 함수를 이용해서 true 라면 픽셀을 써지고 아니라면 안써진다.
그리고 만약에 픽셀이 써졌다면 PASS 를 한것이다 . 그리고 PASS 를 했을때와 FAIL 을 했을때 각각 그 버퍼상의 해당 자리의 스텐실 값을 참조값으로 바꿀지 , 값을 0 으로 대체할지 , 증가시킬지에 대한 여러가지 대처법도 옵션으로 지정할수있다. 그리고 이 모든것은 비트 단위로 이루어지고 , 참조 값과 쓰려는 해당 픽셀 자리의 스텐실 버퍼값과 & 연산으로 이루어진다. 즉 비교 조건이 '같아야할 때' 면은 두 개의 비트가 같아야 한다 . ex) 해당 자리의 스텐실 값 0xff 면 , 참조 값이 0xff 여야 통과.
보통 렌더링 전에 렌더 타겟을 Clear 하는데 이때 스텐실 버퍼의 값을 0 으로 소거했다 가정하고, 참조 값은 0x10 으로 지정하고 ( D24S8 에서 스텐실에 8 비트를 할당하는데 이 의미는버퍼상에 있는 스텐실 값은 0xff 가 최대 값이고 , 참조 값도 0xff 가 최대 값이란 의미임. 0x00 ~ 0xff 만약 이 이상으로 벗어나면 값이 잘리므로 검사되지 않는다 . 즉 0x001 으로 지정해도 0x00 으로 취급된다.)
비교 함수는 "같아야함" 으로 해놓고 pass 시 (통과시,픽셀이써질시) 해당 자리의 스텐실값을 "참조값으로 바꾸기" 옵션으로 해놓고 , fail 시 (실패시,실패안써질시) 해당 자리의 스텐실 값을 "유지" 옵션으로 했다 치자.
자 대략 이 정도의 옵션을 설정했다 가정하고 어떤 픽셀을 렌더한다 . 파이프라인을 거친 후 Z 버퍼 통과후 ( Z 버퍼 실패하면 스텐실 테스트를 아예 하지도않음, 그리고 Z 실패했을때도 따로 해당 스텐실 값을 바꿀수 있는 옵션 있음 ) [3][3] 에 자리가 잡혔다 치자.
그렇다면 이때 검사를 할 것이다 . [3][3] 자리에 현재 스텐실 값은 0 이고 , 참조 값은 0x10 이다.
그리고 비교 함수는 "같아야함" 으로 했으므로 0x00 과 0x10 이 같아야 픽셀이 써진다. 근데 같지가 않으므로 픽셀은 써지지 않는다 . 이때 fail 을 한것이므로 아까 fail 옵션에 "해당 자리의 스텐실 값을 유지" 하는 옵션으로 설정했으므로 [3][3] 의 스텐실 값은 그대로 0으로 유지된다 . 만약 통과했따면 아까 pass 했을때의 옵션으로 스텐실값이 적용 됐을것이다.
| 그림자 부분에만 검정색 그리기
clear로 모든 스텐실값은 0이다.
- (1) 스텐실 버퍼를 킨다.
- (2) 비교 함수를 D3DCMP_ALWAYS 으로 한다. 즉 항상 성공한다 . 즉 검사 자체를 하지 않고 픽셀을 쓴다.
- (3) 참조 값을 0x01 로 설정한다.
- (4) Pass 시 D3DSTENCILOP_REPLACE 을 한다. 즉 해당 자리의 스텐실값을 참조 값으로 바꾼다.
- (5) Fail 시 D3DSTENCILOP_KEEP 을 한다. 즉 해당 자리의 스텐실값을 유지한다.
- (6) 그림자를 렌더링한다. ( 이때 그림자가 그려지는 픽셀 자리에만 스텐실 값들이 0x01 로 교체된다. )
- (7) 비교 함수를 D3DCMP_EQUAL 로 한다. 즉 참조 값과 해당 자리의 스텐실 값이 같아야 한다.
- (8) 검정색 텍스처를 전체 화면 영역으로 해서 그린다.
- (9) 스텐실 모드를 끈다.
댓글
댓글 쓰기