본문으로 바로가기

물체의 테두리(Outline) 그리기 ① - 접근 방법

이번 글에서는 물체의 테두리(Outline)를 출력하는 방법을 다룬다. Shooting게임뿐만 아니라 많은 게임에서 커서로 아이템을 오버랩하면 아이템이 선택되었다는 표시로 물체의 테두리에 아래와 같이 하이라이팅 효과가 나타난다. 이번 글에서는 언리얼 엔진에서 물체의 테두리를 출력하는 방법을 다뤄본다.

▲ [그림 1] 크로스 헤어로 선택된 탄약의 테두리가 하이라이팅 된 모습

먼저 이 기능을 구현하기 위해서는 깊이 버퍼와 렌더링 결과를 텍스처로 출력할 수 있다는 개념을 먼저 이해해야 한다. 이에 대한 글은 예전에 다룬 적이 있다. 깊이 버퍼를 이해하기 위해서 '3D 메시 그리기'에서 Z-버퍼 부분을 그리고 텍스처로 렌더링하는 개념을 이해하기 텍스처로 렌더링 글과 지연 셰이딩 글을 참고하자.

 

Depth Buffer에 대한 이해

언리얼 엔진은 Post Process Material 기법을 제공한다. Post Process란 1차적으로 장면을 렌더링 한 결과를 텍스처처럼 활용할 수 있도록 하는 기법이다.  Post Process Material에서는 Depth Buffer도 활용할 수 있다.  Depth Buffer에는 카메라와 가까운 픽셀일수록 낮은 값을 가진다. Depth Buffer를 출력하면 아래와 같이 회색조 결과를 볼 수 있다. (카메라에 가까울수록 낮은 색상값인 검은색을 보인다.)

▲ [그림 2] (좌) Depth Buffer / (우) 최종 렌더링 결과

언리얼에서는 Depth Buffer 뿐만 아니라 Custom Depth Buffer도 제공하고 있다. Depth Buffer는 화면에 출력될 모든 픽셀들의 깊이값을 가지고 있지만, Custom Depth Buffer는 우리가 지정한 메시의 깊이 값만 가지고 있다. 테두리가 필요한 물체를 Custom Pass에 등록하면 Custom Depth Buffer에는 등록된 메시의 깊이 정보만 출력된다. 우리는 이 Custom Depth Buffer를 활용하여 원하는 물체만 물체의 테두리(Outline)를 추출해낼 수 있다.

 

테두리(Outline) 픽셀 판별하기

어떤 물체 하나를 Custom Depth Buffer에 등록했고 카메라 앞에 있다고 가정하자. 이 물체가 출력될 픽셀에는 카메라로 부터 거리에 따라 깊이 값을 가질 것이다. 그러나 그 외의 픽셀들은 거의 무한대에 가까운 아주 큰 값을 가질 것이다.(실제로 무한대는 아니지만 편의상 여기서는 무한대로 표현하였다.) 물체가 출력될 픽셀이 어느 정도 값을 가지긴 할 테지만 무한대에 가까운 물체 밖에 비해서는 턱없이 작기 때문에 그냥 1이라고 가정하자. 그러면 Custom Depth Buffer에는 아래와 같이 물체가 출력되지 않을 픽셀에는 거의 무한대에 가까운 값이 들어있을 것이고, 물체가 출력될 픽셀에는 1과 같이 작은 값이 들어 있을 것이다.

 

▲ [그림 3] Custom Depth Buffer의 렌더링 결괏값

먼저 각 픽셀의 주변 값(상, 하, 좌, 우, 좌상, 좌하, 우상, 우하 총 8개) 들의 합을 계산해보자. 만약 물체의 테두리에 있는 픽셀이라면 그 픽셀 주변에는 메시 외부의 픽셀이 최소 하나 이상은 존재할 것이다.(아래의 보라색 픽셀) 그리고 테두리가 아닌 내부 픽셀이라면 그 주변 픽셀들도 모두 메시에 해당하는 픽셀일 것이다.(아래의 빨강색 픽셀) 

 

▲ [그림 4] (보라색) 물체의 테두리 픽셀 / (빨간색) 물체의 내부 픽셀

보라색 픽셀처럼 물체의 테두리에 해당하는 픽셀에서는 주변 픽셀들의 합은 여전히 아주 큰 값이다. 하지만 완전히 내부에 있는 빨강색 픽셀에서 주변 픽셀들의 합은 적당히 작은 값을 가질 것이다. 여기서 우리는 테두리 픽셀과 메시의 내부 픽셀(테두리를 제외한)을 구분할 수 있게 된다. 이제 출력을 위해 이를 정규화해보자.

 

모든 픽셀들의 주변픽셀의 합에 10,000,000과 같이 충분히 크지만 외부 픽셀의 깊이 값보다는 훨씬 작은 값을 빼보자.

 

[ 보라색 픽셀 주변 픽셀의 합: ∞ ] - 10,000,000 = ∞ (양수) 

[ 빨강색 픽셀 주변 픽셀의 합: 8  ] - 10,000,000 = 음수

 

메시 외부 픽셀과 메시의 테두리 픽셀들은 최소 하나 이상의 무한대에 가까운 값을 가지고 있기 때문에 10,000,000을 빼더라도 양수를 유지할 것이다. 하지만 메시 내부 값들은 아무리 커도 1,000,000 단위를 넘기기도 어려울 것이기 때문에 메시 내부 값들은 모두 음수가 될 것이다. 이제 음수를 0으로 양수를 1로 정규화하면 아래와 같이 메시의 내부는 0이 되고, 메시의 외부와 메시 테두리는 1인 결과를 얻게 된다.

 

▲ [그림 5] 양수는 1로 음수는 0으로 정규화한 결과

이렇게 테두리 부분과 메시의 내부 부분을 성공적으로 구별해냈다.

 

테두리(Outline) 픽셀만 추출하기

이제 테두리 픽셀만 1로 추출해보자. [그림 3]을 다시 살펴보면 우리는 메시의 외부는 무한대로, 메시의 테두리와 내부는 1로 표현된 최초의 Custom Buffer를 가지고 있음을 알 수 있다. 이번에는 이 최초의 Custom Buffer에서 무한대를 0으로 메시 테두리와 내부는 1로 정규화시켜 아래와 같이 만들어 보자.  

 

▲ [그림 6] 메시 외부는 0으로 메시의 테두리와 내부는 1로 정규화

이제 [그림 5]의 값과 [그림 6]의 값을 서로 곱한다면 아래와 같이 테두리만 1인 결과를 얻을 수 있다.

 

▲ [그림 7] 곱셈을 통해 테두리(Outline)만 추출

이렇게 물체에서 테두리 픽셀만 1인 결과를 얻을 수 있다. 이제 다음 글에서 이 방법을 활용하여 물체 테두리를 추출하는 방법을 구현해 보겠다. 그리고 이 테두리에 색을 입혀 화면에 출력하는 것 까지 다뤄본다.

 

다음글: 물체의 테두리(Outline) 그리기 ② - 테두리 추출하기 >