[Unity] 화면을 게임보이처럼 만들어보자

PublicMinsu·2023년 12월 28일
0
post-custom-banner

개요

출처 : https://youtu.be/FpvJAG6R99k?si=3V7F81XPhykGhcKP

유튜브를 둘러보다 꽤 간단하면서도 괜찮은 셰이더를 발견했습니다.
하지만 문제가 있습니다.

출처 : https://youtu.be/FpvJAG6R99k?si=3V7F81XPhykGhcKP

해당 영상에서는 Renderer Features에 Blit을 사용하여 제작한 것입니다.
지금 제 버전에서는 해당 기능이 없습니다.
그렇기에 이번 글에서는 영상을 따라 하면서도 문제를 해결하는 글이라고 보면 됩니다.

또한 영상처럼 야간투시경이 아닌 게임보이로 수정하여 제작해 보고자 합니다.

Blit

렌더 텍스처

출처 : https://docs.unity3d.com/kr/2022.3/Manual/class-RenderTexture.html

렌더 텍스처는 유니티가 동작 중에 업데이트되는 텍스처입니다.
카메라에 연결하여서 화면을 받아올 수 있습니다.

Blit란?

출처 : https://docs.unity3d.com/kr/530/ScriptReference/Graphics.Blit.html

렌더 텍스처를 복사하는 함수로 셰이더를 적용시켜서 복사할 수 있습니다.

OnRenderImage

출처 : https://docs.unity.cn/kr/2018.2/ScriptReference/Camera.OnRenderImage.html

화면 렌더링이 완료된 후 호출된다고 적혀있습니다.
설명에서도 포스트 프로세싱이 적혀있습니다.

출처 : https://docs.unity3d.com/kr/2021.3/Manual/render-pipelines-feature-comparison.html

'아하! 그럼 OnRenderImage를 활용해서 적용시켜주면 되겠군요!'라고 생각하시겠지만 URP에서는 지원을 안 합니다. OnRenderImage말고 다른 방법을 찾아봐야겠군요.

셰이더 적용하기

Render Objects

지난번에 사용했던 방법을 활용해 보고자 합니다.

NDotL

처음 말씀드렸던 영상에서는 색의 값을 활용합니다.
색의 값 대신 음영의 값은 어떨까요?
NDotL입니다. 빛이 비치는 방향과의 노말 벡터의 방향의 내적을 하여 빛이 비치는 방향의 가까울수록 1의 값을 가지는 연산입니다.
MainLight는 CustomFunction으로 코드를 작성하여 사용하는 노드입니다.

문제점

음영의 값을 활용하여 적용해 봤습니다.
화면에 적용하는 것이 아니기에 아쉬운 느낌이 듭니다.

만약 Event 순서를 변경하면 적용이 안된 모습을 볼 수 있습니다.

원본 오브젝트를 그리는 순서가 찾아오자 덮어씌워진 것을 확인할 수 있습니다.
외곽선의 경우에는 크기가 크기에 살아남았지만요.

해당 문제는 오브젝트의 Material를 변경하는 방식으로도 해결됩니다. Event 순서 변경으로 인해 덮어씌워질 수 있다는 점을 보여드리고자 이렇게 하였습니다. 물론 화면 전체에 효과를 적용할 수 없단 점은 동일합니다.

Vector의 형변환

더 진행하기에 앞서 Vector의 형변환에 대해서 말씀드리겠습니다.

유니티 세이더 그래프에서는 숫자를 다룰 때 차원에 따라 Vector4와 Vector3 ,Vector2, Float로 나뉩니다.
이 4가지가 서로 간에 어떻게 계산이 되는지 알아봐야 위의 동영상을 통해 발생할 수 있는 문제를 이해할 것입니다.

커스텀 Debug 노드

숫자를 확인하고 싶기에 저는 Custom Function을 사용했습니다.

https://gist.github.com/aras-p/657a4947bb8a4549fda53a84bb91fb25#file-debugnode-hlsl

해당 링크에서 가져오시면 됩니다.
위의 사진과 마찬가지로 정확한 수를 나타내진 않지만 대략적인 수는 알 수 있다는 점에서 활용할 가치는 있다고 생각합니다.

Float과 Vector의 연산

Float과 Vector2를 연산해 봤습니다. Float이 Vector의 두 값 모두에 영향을 주네요.
DoDebug의 오류로 값이 잘못 나오긴 했지만 곱하기도 동일합니다.
Vector3도 동일한 것을 알 수 있습니다.
Vector4는 안 봐도 뻔합니다.
즉 Float과 Vector의 연산은 Float이 같은 차원의 Vector가 되어서 계산을 해주네요.

Vector끼리의 연산

Multiply에서부터 차원이 좁혀지는 것을 볼 수 있습니다.
즉 차원이 작은 쪽으로 차원이 옮겨가는 것을 볼 수 있습니다.

Vector의 값을 Float에

그렇다면 Float만 받는 곳에 Vector를 넣으면 어떻게 될까요?

아하 첫 번째 값을 가져가는군요.
Vector끼리의 연산과 동일합니다.

입구의 크기만큼 차원이 좁혀지고 나머지 값은 버려지는 것입니다.
이점을 유의해 주시면 좋습니다.

Full Screen Pass Renderer Feature

출처 : https://docs.unity3d.com/kr/Packages/com.unity.render-pipelines.universal@14.0/manual/renderer-features/renderer-feature-full-screen-pass.html

전체 화면 효과를 생성할 수 있다고 합니다. 또한 이 기능을 사용하면 커스텀 포스트 프로세싱 효과를 생성할 수 있다네요.

즉 저희가 찾는 방법입니다.

사전 준비


Fullscreen Shader Graph를 생성합니다.

URP Sample Buffer를 추가해주고 Base Color에 연결해줍니다.

https://forum.unity.com/threads/undocumented-node-in-shadergraph-for-urp-2022-2-what-does-it-do.1371792/

공식 문서가 없지만 대략적으로 설명해주신 글은 있습니다.
Add Renderer Feature에서 Full Screen Pass Renderer Feature를 선택해 줍니다.
아직까진 그대로입니다.

Combine

영상에서 사용한 Combine에 대해서 알아봅시다.
Split된 값을 다시 합쳐줍니다.


한 곳에만 넣으면 어떻게 될까요?
G에 넣을 시 테스트 결과 Vector 실험 결과와 동일하게 X값만 가져가는군요.
결국 무슨 값을 넣든 1차원 값만 고려될 것입니다.

영상에 나온대로 해봅시다.

테스트

초록빛 세상이 되었지만 색의 기준도 초록빛이 되었습니다.

개선

출처 : https://ko.wikipedia.org/wiki/명도

밝기의 기준을 명도로 바꾸겠습니다. 명도의 경우 직접 계산할 수도 있지만 HSV로 변경해서 사용해도 된다고 생각했습니다.


RGB를 HSV로 변경했습니다.

더 이상 초록이 세상의 기준이 아닙니다.

해당하는 부분은 서브 그래프로 만들어주었습니다. 서브 그래프를 활용하면 재활용, 정리에 용이하다고 생각합니다.

Dither

이후 영상과 동일하게 Dither을 추가해 줍니다.

출처 : https://docs.unity3d.com/kr/Packages/com.unity.shadergraph@10.8/manual/Dither-Node.html

디더링은 고전 게임에서 제한된 색을 활용하기 위해 사용한 기법으로 알고 있습니다. 점으로 찍어가지고 멀리서 보면 색이 섞여 보이게 하는 기법입니다.

Dither의 크기를 조절하시고 싶으시면 나눗셈을 하시면 됩니다.
나눗셈보단 곱하기가 빠르니 1이하의 값으로 곱해주시면 됩니다. 아니면 가독성을 위해 Divide를 사용하셔도 됩니다.

어둡긴 하지만 그럴싸합니다.

원본과 비교하기 위해 모든 효과를 빼고 가져와봤습니다.

Dither만 추가해 보았습니다.
Dither가 기본적으로 어둡게 만든다는 걸 알 수 있습니다.

영상에서 한 것과 동일하게 0.5를 더하여 원본과 유사한 색을 가져왔습니다.

더한 값을 기준으로 다시 적용해 보니 괜찮은 색상이 나왔습니다.

Sample Gradient

출처 : https://docs.unity3d.com/kr/Packages/com.unity.shadergraph@10.8/manual/Sample-Gradient-Node.html

Time에 따라 벡터 4 컬러 값을 가져오는 것입니다.

0부터 1까지의 값에 따라 Gradient에서 색을 가져오는 것을 볼 수 있습니다.

영상에서는 이를 이용해 음영을 강조했습니다.

Combine을 버리고 이것을 활용해 보는 건 어떨까 싶었습니다.

게임 보이 필터로 말입니다.
명도에 따라 색을 변환시켜줍니다.

만약 원본 화면으로 전환하고 싶다면 Lerp를 사용해 주면 됩니다.

테스트

일단 처음에는 게임보이 효과를 주고 원래의 화면으로 돌아가게 찍어봤습니다.
원하는 대로 작동합니다.

느낀 점

Full Screen Pass Renderer Feature는 화면을 수정해 주는 점에서 유용합니다.

아무래도 게임 보이 화면 효과가 외곽선을 그린 뒤에 작동하기에 외곽선의 색이 검은색이 아닌 초록색 계열로 보입니다. 그러한 점을 피하고 싶다면 렌더링 순서를 변경하셔도 됩니다. 또는 변형되지 않게 색을 조정하시는 방법이 있습니다.

지금 만든 화면 효과는 평상시보단 특정 상황에서 사용할 생각입니다.

profile
연락 : publicminsu@naver.com
post-custom-banner

0개의 댓글