그래픽(기타)

(스터디 간접참여)유니티 SRP 셰이더 그래프 - 1

에페아 2019. 12. 29. 15:57

교수님의 도움으로 셰이더 스터디에 간접적으로나마 참여할 수 있게 되었습니다

 

이전 이펙트 과제를 srp환경에서 한적이 있었다보니 인터페이스는 나름 익숙해졌는데

셰이더 자체에 대한 지식이나 이해 같은 부분이 부족해서 꼭 듣고싶었죠

감사합니다 교수님ㅠㅠㅠㅠ

 

글은 으음... 그냥 제가 봐서 이해할 수 있을 정도로 쓸겁니다(아니이사람이)

 

제목에도 써있다시피 SRP환경(HDRP/URP/아니면 직접 커스텀한거)에서 진행합니다

 

1. 인터페이스 설명

-셰이더 생성 / 전체 인터페이스

-블랙보드의 효율적(이라고 말하지만 기본적인) 사용법

 

2. 색 연산에 대한 고찰

-srgb, 리니어, 감마

-그래서 정상적으로 보이게 하려면

 

1. 인터페이스 설명

이제 막 시작했으니 뭐라도 건드려봅시다

-셰이더 생성 / 전체 인터페이스

일단 제일 먼저 그래프 셰이더를 생성해봅시다

1. Project 바로 아래 있는 '+' 클릭(아니면 Assets에 오른쪽 클릭하고 Create 탭 들어가기)

2. Shader 탭을 엽니다

3. 저 빨간 네모박스 안에 있는 3개 중 원하는 걸 선택합니다

 

Unlit : 빛 안받는거 (Lit이 빛? 뭐 대충 비슷한 뜻인가봐요)

PBR : 빛 받는거

VFX Shader : 처음에 이거보고 '오 이게 그 파티클 수백만개 뿌릴 수 있다던 그건가??' 하고 설레발했지만 그놈이 아니라 실망했던 셰이더입니다

 

그리고 사실 이펙트 만들때도 VFX Shader 안쓰고 다 Unlit 그래프 썼던지라 딱히 메리트가 있어보이진 않는...

굳이 메리트가 있다면.... 항목이 간단하다 정도......?

 

자 이제 셰이더를 열어봅시다

저는 PBR Graph로 만들었습니다

셰이더를 처음 생성하고 열어보면 이런 광경이 나오는데

그냥 열어놓기만 하면 멍해지니 분류를 한번 해봅시다

1. 블랙보드

변수들 모아놓은 공간이라고 보면 편합니다

어... 음...... 그러니까 제대로된 설명은 뒤에서 할게요

 

2. 프리뷰

미리보기라고 보면 됩니다. 이름 대로 '프리뷰'

 

3. 나머지영역

이 공간에서 셰이더를 짜게 됩니다 막 이것저것 블록 만들어가지고 서로 연결시켜놓고 그런 공간이요

 

혹시나 블랙보드나 프리뷰의 크기를 조절하고 싶다면

저 오른쪽 아래에 빨간 네모 친 '_' 이걸 누른 상태로 드래그 하시면 됩니다

 

크기를 원하는 대로 조절하셨다면 이제 노드를 생성해봅시다

빈공간에 마우스를 대고 우클릭 하거나, 스페이스바를 누르면 Create Node 창이 뜨게 됩니다

거기에 있는 노드를 우리가 갖다가 이어붙여서 셰이더를 짜는 것이죠

카테고리를 나눠놓긴 했지만 솔직히 뭐가 어디에있는지는 잘....

한번 시험삼아 vector 노드를 생성시켜봤습니다

노드 찾을 땐 검색 쓰세요 두번, 세번 쓰세요

저렇게 어찌저찌 해서 vector를 찾아서 클릭하면 오른쪽과 같이 vector노드가 생기게됩니다

그리고 연결은 저 구멍난 동그라미를 드래그 하면 되죠

무슨무슨 노드가 있는지는 뭐... 노드가 한두개인 것도 아니니 그냥 조작법만 익히고 일단은 넘어갑시다

 

아, 그리고 셰이더 페이지를 따로 빼놓으면 자꾸 사람 짜증나게 창이 이따구가 되는데

해결법은 그냥 창 크기를 살짝 조정하면 바로 풀립니다

 

아예 이런 현상이 안나오게 할 수 있는 방법은 음...

몰라요 저도 그냥 갑자기 자기알아서 저리 되는데 뭐 어쩌겠어요 유니티에서 고쳐주길 바래야지

 

뭐 어쨌든 다시 돌아와서

방금 생성했던 vector4 노드를 한번 들여다봅시다

뭔가 감이 오시거나 딱 알겠다 싶으시다면 당신은 이미 배운 아티스트이시거나 프로그래머입니다

저 X, Y ,Z, W, 그리고 Out 옆에 딸린 괄호 안의 숫자.

각 변수가 몇개의 숫자를 가지고 있는지를 나타내는 숫자입니다.

 

자 더 구체적으로 하자면

x가 가리키는 값은 0 하나고

y가 가리키는 값도 0 하나,

z, w도 마찬가지로 0이라는 숫자 하나를 가리키고 있죠

그래서 괄호 안에 숫자가 1인 겁니다

 

근데 Out은 괄호 안 숫자가 4죠?

공교롭게도 왼쪽에 있는 변수도 4개네요?

즉 Out은 x, y, z, w의 값. 즉 4개의 숫자를 가지고있는 아이입니다. 그래서 괄호 안의 숫자가 4인 것이죠

(Out으로 한마음이 되었다)

그렇게 한마음이 된 Out을 마스터노드에 있는 Albedo에 넣어줍니다

albedo가 정확히 뭔뜻인지는 모르겠는데 그냥 출력할 색의 기본값? 비슷한 건가봐요

여기다가 노말 섞고 에미션 섞고 뭐 섞고 알파 넣고...?

어 근데 albedo는 괄호 안 숫자가 3인데요?

 

우린 알고 있습니다 지들 내부에서 알아서 형변환이 이루어지고 있다는 사실을...

 

대충 설명하자면

우리가 큰컵에 물을 가득 담고 그 물을 그대로 작은 컵에 담게 되면 어떻게될까요

작은 컵의 용량만큼만 담기고 그 후로 들이붓는 물들은 컵에 안담기고 다 넘쳐흐르겠죠

데이터도 마찬가지입니다

Out은 4개의 숫자(x,y,z,w)를 가지고 있죠 하지만 albedo는 3개의 숫자(뭐 대충 x, y, z로 씁시다)만 가지고 있습니다

albedo가 용량이 더 작아요 그래서 Out을 담으려고 하면 넘쳐버립니다

그렇게 넘친 결과 Out의 맨 끝에 있는 w는 버려지게 되고, 앞의 x, y, z만 albedo로 넘어가게 되죠

 

즉, 

Out(1, 2, 3, 4) 를 albedo로 넘기게 되면 -> albedo(1, 2, 3) 이 되고, 4는 그냥 갖다버립니다

그럼 숫자 2개를 받는 Vector2로 넘기면 어떻게될까요?

Out(1, 2, 3, 4) -> Vectot2(1, 2) 이렇게 받고 3, 4는 버립니다

 

다 됬고 그냥 무조건 같은 용량끼리만 묶으세요 저렇게 그냥 놔두면 안돼

 

뭐 어쨌든 연결을 잘 시켰으면 프리뷰가 까만색 공이 될겁니다

x,y,z(r,g,b)값이 다 0이니 프리뷰에 검은색이 나타나죠

자 이제 (블랙보드를 뺀)기본적인 노드 생성 / 잇기는 할 수 있을 것 같아요

 

그럼 이제 블랙보드로 넘어갑시다

 

-블랙보드의 효율적(이라고 말하지만 기본적인) 사용법

사실 블랙보드 자체는 그냥 딱히 설명할 것도 별로 없긴 한데

어떻게 쓰는 게 좋을까 하고 설명을 덧붙이면 좋을 것 같아서 따로 빼놨습니다

솔직히 활용법은 각양각색이라 여기에 써놓은 건 제 주관적인 내용이긴 하지만요

 

이름과 생김새를 듣자마자 딱 느껴졌습니다

'아 요거 언리얼에 있는 블랙보드같은 개념이구나...' 하는 걸요

언리얼에 구현되있는 블랙보드
보드에 변수를 생성시키고 그걸 외부에서 갖다 씁니다

사용법도 그냥 비슷비슷하더라고요

보드에 변수 만들어놓고 노드로 끌어와서 갖다쓰고

 

그럼 유니티에선 블랙보드에 변수를 어떻게 생성시키느냐

블랙보드 오른쪽 맨위 '+' 버튼 누르면 만들 수 있는 변수 목록이 쫙 뜹니다

주로 쓰는건 Vector계열, Color, Texture2D, Cubemap(근데 큐브맵은 어... 구름 흘러가게 할 때 셰이더쓰나...?), Boolean 정도...? 인 것 같아요 아마도.

 

시험삼아 Vector4로 한번 생성해봅시다

위에서부터 차례대로 보자면

MyVector4 : 요거 그냥 제가 지은 변수 이름이에요 님들은 알아서 마음대로 지으세요

더블클릭 하면 저렇게 이름을 바꿀 수 있습니다

Exposed : 요거 체크해놓으면 유니티 콘솔에서 값을 조절할 수가 있게됩니다

요런식으로요

Reference : 외부 코드에서 이 값에 접근하기 위한 이름입니다

요 이름을 갖다가 스크립트에서 호출하면 마음대로 값을 빼오거나 넣을 수 있죠

이런식으로 블랙보드 데이터 값을 로그로 찍는 코드를 쓰면
그대로 값이 찍힙니다

그러니까 플머한테 넘겨줄거면 저 이름 기본상태로 놓지말아주세요 확 리소스 파일 이름 다 asdf1234로 갈아끼워버릴라

 

Default : 처음에 아무것도 안만졌을 때 어떤 값으로 놓을 건지를 정합니다. 기본값 설정하는거죠 그냥

만약 저기에 x를 1로 해놓고 머테리얼에 이 셰이더를 넣고 보면 MyVector4가 0,0,0,0이 아니라 1,0,0,0으로 시작하는 걸 볼 수 있습니다

 

Precision : 정밀도라고 하는데 소수 자릿수를 얼마나 정밀하게 계산할건지..? 대충 그런건가봐요

Inherit: : 상속, Float : 열라 큰거, Half : Float의 절반(보통 이걸 쓴다 하는데 그냥 Inherit로 놔둬도 문제는 안되는 것 같아요 아마..?)

Hybrid Instanced : 저도 모르겠어요 그리고 어차피 실험중이래요 검색해도 바로 딱 나오진 않는 것 같고...

그냥 넘기죠

 

아그리고 하나 빼먹은 Mode 라는 아이가 있습니다

얘는 아마 Vector1이나 다른 특정 변수들한테만 있을거에요

안에 들어있는 보기들도 약간 다르고

Vector1에는 Default, Slider, Integer, Enum이 있네요(근데 Default나 Slider를 주로 쓴대요)

그럼 이제 대략적인 블랙보드에 대한 조작은 다 된 것 같고,

 

그럼 요놈을 좀 더 활용할만한 방법을 찾아봅시다

 

1 - 필요한 것만 콘솔에 보이게 하고 최대한 블랙보드 내 자료를 숨겨놓는다

2 - Vector4 == Vector2 == Vector3(???)

 

1 - 필요한 것만 콘솔에 보이게 하고 최대한 블랙보드 내 자료를 숨겨놓는다

가장 쉽게 예로 들 수 있는게 스크립트 내에서 만질 값들이겠네요

얘네는 코드로 만질 애들이니까 굳이 유니티 콘솔에 비치게 할 필요는 없겠죠(디버그용으로는 보이면 좋기야 하겠다만 아티스트 입장에서는 으음... 그리고 사실 굳이 안빼놔도 플머들은 값 알고싶을 때 로그 찍게 코드짜면 되거든요)

 

예시로 간단하게 흑백 셰이더를 만들어봅니다

이 셰이더는 블랙보드의 IsGray의 값에 따라 흑백을 먹일지 안먹일지를 결정합니다

 

만약 처음부터 '얘는 무조건 흑백이야' 또는 '얘는 무조건 칼라야' 라고 딱 정하고싶다면야 그냥 Exposed 체크하고 콘솔에서 조절하면 되겠죠

 

하지만 만약 플레이하는 중에 'G 키를 누르면 흑백, C 키를 누르면 컬러가 되게 하고싶다' 라는 걸 구현하게 된다면?

이건 전적으로 스크립트 내에서 컨트롤하기 때문에 굳이 유니티 콘솔에 IsGray를 빼놓을 필요가 없겠죠

 

그리고 굳이 만질 필요가 없는 건 빼고 필요한 것만 콘솔에 빼놓으면 아티스트도 만들어진 셰이더를 더 원활하게 사용할 수 있겠죠 아마..?

플레이 전에 IsGray 체크를 풀어놨더라도...
스크립트에서 값을 수정해버리면 아무 의미가 없다

2 - Vector4 == Vector2 == Vector3(???)

이게 뭔소린가 싶죠?

저도 뭔가 싶어요 대체 왜 이따구로 만들었는지

 

이부분은 최적화에 대한 부분이긴 한데 실제로 이게 어느정도 영향을 줄지는 모르겠어요

근데 뭐 해서 나쁠건 없잖아요?

 

자 이게 뭔소린가 싶으니 바로 실험 들어갑시다

Vector2 변수와 Vector3 변수를 각각 준비해줍니다

자 이걸 유니티 콘솔에서 보면 당연히 MyVector2는 숫자2개를 입력할 수 있을 것 같고, MyVector3은 숫자3개를 입력할 수 있게 되있을 것 같죠

 

하지만 결과는...

'으응?~ Vector4라 잘 안들리는거얼??'

ㅎ..ㅎㅎ.. 아니 그냥 보기에만 저렇게 되있고 사실 다 가짜 값일 수도 있잖아요

그냥 콘솔에서 표시만 저렇게 해두고 메모리상에선 Vector2일 수도 있고...

 

해서 로그를 찍어봤습니다

'안돼 그런거 없어 돌아가'

Vector2, Vector3 모두 Vector4로 나오는 것과 함께 차지하는 메모리도 Vector4의 크기인 16바이트를 먹는 것을 볼 수 있었습니다....

 

그럼 마지막으로 소스코드를 확인해봅시다

굉장히 선명하게 (0, 0, 0, 0) 4자리가 적혀있다

네 그냥 Vector4네요

 

아니 그럼 이놈들은 대체 뭔생각으로 나눠놓은거야

 

뭐... 그럼 어쨌든 Vector1이 아닌 이상 다른 벡터들은 무조건 Vector4로 연산이 된다는건데

그렇다면 Vector2를 써도 Vector4가 생성되는 거니까 결국 뒤에 z, w 부분은 버려지게 된다는 거겠죠?

 

그게 좀 아까워서 그냥 아싸리 Vector4로 만들어서 여러 데이터를 넣어버리는 생각을 했습니다

 

예를 들기 위해 전에 짜놨던 셰이더를 갖고와보죠

tiling이랑 offset을 콘솔에서 설정할 수 있게 빼놓은 구조

tiling이랑 offset 모두 x,y값만 가지는 Vector2 형태입니다

근데 이걸 진짜로 블랙보드에 Vector2 두개를 만들어놓으면 실상은 Vector4가 두개 생성되는것이고, 안쓰는 숫자가 4개니까 결국 전혀 쓰이지 않는 Vector4 변수 하나를 그냥 만들어놓은 것과 같게 되죠

 

그래서 이걸 아싸리 Vector4로 받아버려서 x,y는 tiling연산에서 x,y로 쓰고, z,w는 offset연산에서 x,y로 써버리는 겁니다

그러면 메모리 낭비 없이 사용할 수 있겠죠?

물론 이게 최적화에 그렇게 커다란 영향을 미칠 것 같지도 않고, 너무 이런 방식을 남용하면 가독성에도 안좋을 수 있지만 나름 적절히 사용하면 좋은 테크닉이 될 수 있지 않을까...? 하는 생각에서 글에 넣어봤습니다

 

2. 색 연산에 대한 고찰

- srgb, Linear, Gamma

이부분은 사실 

https://www.slideshare.net/jpcorp/ss-96115075

 

감마가 어디감마

유나이트 2018 'Artist를 위한 Gamma Correction과 Linear Rendering'

www.slideshare.net

요 슬라이드를 보면 되긴한데...

 

솔직히 말할게요

한 5번은 돌려봤는데 정확한 설명은 못하겠어요 그냥 대충 감각적으로만 이해했지

 

그래서 대충 나름 이해한 대로 간략하게 설명하자면..

sRGB = 모니터에서 보는 것보다 밝은거(저 아래 두개로 보정먹이기 전, 밝은 상태)

Linear = 모니터에 정상적으로 보여야 되는 거 (선형그래프)

Gamma = Linear에서 대비 높인거(비선형그래프)

 

그리고 모니터같은 화면에서 sRGB 그대로 겁나 밝게 안나오는 이유는 Linear든 Gamma로든 보정먹여서 보여지기 때문이다 정도로 이해를 했는데 어... 이부분은 맞는지 모르겠어요

 

암튼 그래서 이정도 이해한 토대로 지금 문제를 대면하자면

둘다 똑같이 0.5+0.5를 했는데 다른 결과가 나온다

아니 0.5+0.5는 1이니까 당연히 하얀색이 나올 줄 알았어요

나오긴 나오는데 벡터로 연산할때만 하얀색이 나오고 컬러값으로 하니까 회색이 나오네요?

 

사실 답은 교수님이 다 알려주셨지만 그래도 한번 적어보죠

이렇게 적혀있는데

프로젝트 칼라스페이스가 감마로 되있으면 받은 색 그대로 출력이고, 리니어면 srgb->리니어로 보정하는 작업을 해서 출력을 시킨다네요

 

즉, 우리는 그냥 0.5를 쓰고싶었던 건데 얘네들이 지맘대로 '어 야 이거 sRGB(니가 원하던것보다 밝은거)지? 우리가 보정해줄게' 하면서 출력값을 더 어둡게 보정해서 만들어버린겁니다

 

- 그래서 정상적으로 보이게 하려면

1. 진짜로 더 밝게 보내버린다

2. 연산할때 칼라스페이스를 바꿔버린다

 

1번의 경우 그냥 값을 곱해서 보내면 끝입니다

우리가 궁금한건 2번이죠

 

노드 중에 Colorspace Conversion이라는 노드를 가지고 리니어->RGB로 바꿔주니까

컬러값끼리 계산해도 제대로된 출력이 나오네요

 

 

----------------------------------------------------------------

아 다음부턴 글 짧게쓰는 연습좀 해야겠네요

 

 

반응형