[Unity Shader] 간단한 Cloak 쉐이더

2023. 11. 2. 07:45배움엔 끝이없다/그래픽스

이 글은 유니티 코리아 유튜브 채널에 있는 유니티 셰이더그래프 튜토리얼 3 : 투명망토 효과(cloaking, stealth) 를 참고해 초보자가 학습한 내용입니다.

요약

위와 같은 투명인간 효과를 위한 쉐이더를 구현합니다.
쉐이더는 크게 아래의 과정으로 이루어집니다.

  1. 기본적인 씬이 렌더링 된 후에(Transparent 단계) 실행되어, 현재 픽셀 위치의 Screen Color를 불러와 표시한다.
  2. 현재 픽셀 위치에 vertex normal값을 더해줘 왜곡을 준다.
  3. Fresnel 효과로 외곽선 부분에 색을 넣는다.

Cloak 쉐이더

전체 쉐이더

Screen Color 구하기

우선 렌더링 파이프라인 애셋에 Screen Color를 버퍼에 담도록 설정해야한다.

Rendering Pipeline Asset 상단부

여기서 Opaque Texture를 체크해주면 되고, Downsampling을 지정해 버퍼의 해상도를 고를 수 있다.

쉐이더 그래프에서 Scene Color 노드로 해당 버퍼를 받아올 수 있다.

Scene Position을 Scene Color의 입력으로 넣고 바로 출력하면 아래같은 투명 효과를 얻을 수 있다. (픽셀의 위치에 있는 값을 그대로 그렸기 때문)

Scene Color를 출력한 부분의 이미지만 해상도가 좀 떨어져 보이는건 Downsampling을 2x Bilinear로 했기 때문이다.

Normal을 더해 왜곡 주기

View Space의 Normal을 입력을 가져온다. View Space인 이유는 왜곡이 카메라를 기준으로 일어나야하기 때문이다.

이 Normal 값의 x,y 값을 가져와 앞선 Screen Position에 더한 후 그 위치의 Screen Color를 가져오면 된다.

- 이 때 Normal의 값이 크기 때문에 WarpScale이라는 속성을 만들어 곱해준다.

- x,y값을 가져오는 이유는 View Space에서 z는 깊이를 의미하는데, 현실에서 깊이에 따른 왜곡은 거의 없기 때문이다.

Fresnel 효과 추가

Fresnel 효과는 View 각도와 표면 사이 각에 따라 효과를 줄 때 사용하는 함수로, Specular Light 계산을 할 때 쓰인다.

특별한건줄 알았는데 1 - dot 를 n제곱 한 값으로, 1-dot를 좀더 극단적으로 만들어주는 함수다.

void Unity_FresnelEffect_float(float3 Normal, float3 ViewDir, float Power, out float Out)
{
    Out = pow((1.0 - saturate(dot(normalize(Normal), normalize(ViewDir)))), Power);
}

여기서 saturate는 clamp01과 완전히 동일하다. 차이를 찾아보려했지만 컨벤션의 차이 정도 인 것 같고, 하드웨어에 따라 명령어 지원 여부가 다른 것 같았다. 관련 논의를 보니 saturate를 사용하라는 쪽이 좀더 우세한 것 같다.

View Direction과 Normal를 입력으로하고 Power에는 속성을 만들어 넣고, 색을 곱해준 뒤 최종 Scene Color에 곱해주면 된다.

쉐이더 결과

이런 계산 방식 때문에 생기는 몇가지 특징들이있다.

1. Cloak 가 2개 겹쳐도 이중으로 왜곡되지는 않는다.

머테리얼을 동일하게 사용하기 때문에 자동으로 Batching되어, 두 모델이 같은 Scene Color를 사용하게 된다.

2. 다른 오브젝트 뒤쪽에 Cloak를 두면 오브젝트 앞면이 비춰진다.

모든 오브젝트를 그리고나서 Transparent단계에 normal 만큼 offset된 Screen Color를 가져오기 때문에,

그리고 Depth Buffer를 활용하려해도 해당 모델 뒤쪽에는 뭐가 있었는지 알 수 없기 때문에

다른 오브젝트가 앞에있는지 뒤에있는지는 신경쓸 수 없다.

이를 해결하려면 Cloak를 기준으로 앞에있는 것과 뒤에 있는 것의 렌더링 순서를 나눠야할 것 같은데, 플레이어만 Cloak하는게 아니라 그런게 여러개있다면 활용할 수 없는 방법이다. 또, 플레이어만 있다고 하더라도 한 모델 내에서의 깊이 차이는 어쩔 수 없다.

반응형