[UE5] 2. Mesh Outline
이전 게시글인 '돌 캐기'에서 캘 수 있는 돌을 인식하는 방식은 다음과 같다.
- 플레이어가 광물에 접근한다.
- 각각의 광물이 가진 Box Collider와 Player의 Collider가 Overlap된다.
3인칭 시점이기 때문에 선택한 방법인데
역시 너무 낭만이 없다 싶어서 바라보는 돌을 캐는 방식으로 만들어봐야겠다 싶었다.
이 글에 작성될 내용은,
보는 중인 돌을 캐게 만들기 위해 첫 번째로 한 작업인, 바라보는 중인 액터에 아웃라인을 표시하는 것이다.
아래로 적을 코드들은 결국 모두 유튜브(https://www.youtube.com/watch?v=1XqXvVFN5i4)의 튜토리얼을 따라한 것이다.
만약 영어를 잘한다면 뭔가 설명도 잘해주고 있으니 들어가서 직접 보는 것을 추천한다.
한글로 된 자료는 https://m.blog.naver.com/wkdghcjf1234/222036641148 이 블로그에서 볼 수 있었다.
(구현된 코드가 조금 다르긴 하지만 원리 자체는 아마 같다)
자세한 구현 방식을 길게 적어보려 했으나, 위의 두 게시글에서 설명이 너무 잘 돼있으니,
나처럼 아예 처음 렌더링 쪽에 접하게 된 사람들을 위해 용어에 대한 간단한 정리와 요약만 해보기로 했다.
구현 과정에서 계속 쓰이는 용어는 대충 아래 3개인데, 완벽한 설명은 아니니 이해에 도움을 주는 정도로만 생각해주세요.
- Depth : 렌더링 될 오브젝트와 나의 거리.
- Texel : UV에 따라 결정되는 실제 텍스처 매핑 값
- Stencil value : 오브젝트가 갖는 렌더링에 사용될 변수
Outline을 구현하는 과정은 다음과 같은데,
- Depth를 이용해 오브젝트를 구분한 후, 화면의 각 택셀에 대해 상하좌우 픽셀값을 가져와 Outline인지 아닌지 구별한다.
- Outline이라면 색을 칠한다.
먼저 Outline의 구별법은 네이버 블로그에서 잘 설명돼있는데, 네이버에서는 8방향, 유튜브에서는 4방향으로 구현됐다.
스크린 내의 모든 픽셀에 대해서는 다음과 같이 4방향에 Depth 값을 가진 픽셀들이 존재한다.
이 4방향의 픽셀과 중앙의 자신이 같은지를 "[중앙값 * -4] + [4방향 값의 합] 이 0인가?"라는 방법으로 확인하는 것이다.
이 때 울퉁불퉁한 오브젝트라면 유의하지않은 정도의 값이 발생할 수있으므로 (계산 결과가 1 미만인 경우)
Floor를 통해 소수점을 모두 내림 해버리고, True/False로 구분하기 위해 0~1로 Clamp 해줬다.
이를 통해 1미만 값들은 전부 내림으로 0이 되었고, 1 이상 값은 Clamp로 1이 되었다.
여기서 값이 1인 부분이 Outline이 된다.
그러면 Outline만 1이 됐으니, 0인 부분에는 원래 색을, 1인 부분에는 Outline의 색을 칠해줘야한다.
원래 색을 구하는 방법은 'SceneTexture:PostProcessInput'을 이용해주면 되고,
따로 적용하는 것은 Lerp를 이용해, A(0)에는 원래색, B(1)에는 Outline의 색을 입력해준다.
이렇게 하고나면 커다란 문제가 하나가 있는데, SkyBox가 원형으로 플레이어를 둘러싸고 있으므로, 같은 Depth로 계산된다는 부분이다.
그렇기 때문에, 하늘을 보거나, 넓은 평지로 가면 바닥이 뭔가 둥글게 되면서 Outline색으로 칠해지는 것을 볼 수 있다.
이를 해결하기 위해, Scene Depth가 일정 수치 이상이면 Lerp 0값을 줘서 원래 색으로 바꿔준다.
여기까지하면 모든 오브젝트에 Outline이 생긴다.
내가 원하던 것은 특정 오브젝트에만 생기는 것이므로, Custom Stencil을 사용한다.
오브젝트에 Stencil값을 입력하고, PostProcess material에서 'SceneTexture:CustomStencil'을 이용해 오브젝트의 Stencil값을 받아온다.
이 값이 지정해둔 숫자와 일치한다면 Outline의 색을, 아니라면 원래 색을 출력하도록 Lerp 노드를 이용해 구성해준다.
여기까지 하면 원하는 오브젝트에만 Outline을 입힐 수 있다.
여기서 하나 문제점이 있는데, Unreal Forum을 돌아다녀본 결과 5.2에서는 업데이트가 될 내용이라고 한다. (현재 5.1)
바로 Nanite Mesh에는 Stencil을 적용할 수 없다는 것인데, 이를 해결하기 위해 Outline을 구현한 액터에 Parent Actor BP를 하나 만들어서, 원래 메시 밑에 원본을 복제하는 자식 메시를 하나를 더 만든다.
자식메시는 Nanite Disallow가 켜져있고, 렌더되지 않음 옵션을 켜 보이지 않게 해준다.
그리고 이 자식 메시에 Stencil값을 입력하면 잘 작동한다.