일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- normal map
- 게임개발
- 손맵
- Colorize
- 3d 뷰어
- 3d 모델을 로드할 수 없음
- fbx 안열림
- 방학셰이더스터디
- 게임제작
- fbx
- 재질
- 유니티
- 배경모델링
- fbx 보안
- 노말맵
- 모작
- 셰이더그래프
- 컬러라이즈
- 3D AI
- 검색 프로그램
- 메가스캔 유료화
- 엔진심화
- 메가스캔
- 3d 모델링 ai
- 프로젝트
- 모델링 ai
- pureref
- rodin ai
- 공부
- 레퍼런스 프로그램
- Today
- Total
베개발
03. UV 응용하기 본문
계속해서 스터디 진행중입니다.
목차
-
UV 복습 - UV란? - u와 v 축
-
UV 계산하기 - UV 이동하기 - UV 확대/축소하기 - 응용해보기
-
Time 노드 - 움직이는 UV
-
굴절시키기 - 움직임의 강도 (0~1)
-
불 이펙트 만들기
-
디테일 맵 만들기 - 디테일 맵이란? - 만들어보기
추가로 해보기
*개인적으로 공부하면서 추가로 조사해본 것들이므로 추후 스터디 내용과 겹칠 수 있습니다.
-
스크린 스페이스 UV - 스크린 스페이스란? - UV 움직이기
-
스크린 컬러 - 카메라에서 가져오기
-
디스토션 셰이더 - 만들어보기
-
배운 것 다 합쳐보기 - 개인 작업
1. UV 복습
UV란?
저번 글에서 UV에 대해서 설명을 드렸습니다.
간단히 말해서 버텍스의 정보에 대응하는 (0,0)에서 (1,1) 까지의 공간을 말하는 것입니다.
생각해보면 여기서 나오는 0과 1도 똑같이 색으로 표현할 수 있지 않을까요?
각각 R채널과 G채널에 넣는다면 어떻게 보일까요?
이렇게 (0,0)부터 (1,1) 까지 있는 공간이 있고,
그래프상의 x축 (가로축)은 U축에 대응되며,
그래프상의 y축 (세로축)은 V축에 대응됩니다.
R과 G는 0에서 1로 갈수록 세게 출력됩니다.
그리고, R과 G가 둘다 1로 출력되면 가산혼합 되어 노란색으로 보이게 됩니다.
그렇다면 결론적으로 아래와 같은 모습이 되지 않을까요?
어디서 많이 본 것 같은 익숙한 그림이 나왔습니다.
이게 바로 UV좌표 공간을 각각 R과 G라는 채널로 표현한 값이었던 것입니다.
+ OpenGL과 DirectX UV 차이 알아보고 가기
OpenGL과 DirectX는 UV좌표가 조금 다릅니다.
아래 이미지를 참고하시면 됩니다.
유니티에서는 OpenGL UV 좌표를 사용합니다.
u와 v 축
각각을 보면 좀더 직관적으로 이해할 수 있습니다.
UV 좌표의 (0,0)부터 (1,1) 까지 각각 R과 G값을 이용해서 표현하고 있다는 것을 쉽게 알 수 있습니다.
2. UV 계산하기
아마 여기까지 잘 따라오셨다면 색이 더이상 색이 아니라 숫자로 보이는 현상을 겪으셨을 것이라고 생각합니다.
그렇다면 저 UV도 숫자로 이루어져 있는거니까, UV좌표에도 계산을 할 수 있지 않을까요?
간단하게 add 연산을 한다고 생각해봅시다.
새 unlit 셰이더그래프를 만들고, 아래 사진처럼 노드를 배치해주세요.
add노드에 붙은 vector1은 블랙보드로 빼서 인스펙터 창에서 보이게 해주세요.
그 다음, 값을 자유롭게 조정해보세요.
어떤 식으로 움직이는지 바로 확인할 수 있습니다.
UV에 일정 값을 더하는 것을 맥스에서 나타내보자면 이렇게 됩니다.
gif 상에서는 U축과 V축 동일하게 약 0.3만큼 더했다고 치면,
맨 왼쪽 아래 버텍스를 기준으로 (0,0) 에서 (0.3,0.3)이 된 것입니다.
나머지 버텍스들도 똑같이 움직입니다.
만약 UV좌표가 (0.5,0.5)인 버텍스가 각각의 축에 0.3씩 더해졌다고 치면 (0.8,0.8)이 됩니다.
곱하기 연산도 가능합니다.
아까 그 노드에서, add 전 단계에 multiply 노드를 추가해주세요.
역시 곱해주게 되는 숫자는 property로 빼주세요.
그런 다음, 다시 플레이 화면으로 돌아와서 곱해주는 수를 조절해보면,
이런 식으로 이미지가 확대/축소됩니다.
이것 역시 맥스에서 표현해보자면,
예를 들어 UV에 0.5만큼을 곱한다고 친다면, 원래 (0,0)에서 (1,1)까지를 담았던 것을 (0,0)에서 (0.5,0.5) 까지밖에 담지 못하게 되므로
UV가 이미지상의 더 좁은 곳밖에 표현하지 못하게 돼서, 결론적으로 이미지가 확대되어 보이는 것처럼 변하게 된다는 것입니다.
헷갈리신다면 일종의 카메라 같은 원리라고 생각하셔도 됩니다. 만약 카메라가 작아진다면, 더 좁은 곳밖에 담지 못하겠죠. 그런 원리입니다.
그렇다면, 유니티에서 만들었을 때 왜 이미지가 반복되는 것일까요?
이미지 파일을 선택한 뒤 인스펙터 창을 보시면,
밑에서 3번째에 Wrap Mode라는 것이 있고, 현재 설정이 Repeat입니다.
repeat는 반복한다는 뜻이고, 즉 저 설정의 의미는 (0,0)~(1,1) 안에 들어오지 않는 UV 영역에 대해서는 이미지를 반복시켜서 넣겠다는 의미입니다.
즉 이런 느낌으로 이미지가 반복된다는 것입니다.
우리가 맥스에서 UV를 언랩할 때, 가운데에 있는 사각형 공간에만 UV를 피는 것이 바로 이런 원리 때문입니다.
그 공간은 (0,0) 부터 (1,1) 까지의 공간을 나타내는 것이었고, 그 밖의 공간은 결국 가운데의 (0,0)~(1,1) 공간이 반복되는 것이었습니다.
Repeat 말고도 다른 옵션들도 있습니다.
Clamp, Mirror, Mirror Once, Per-axis 옵션이 있습니다.
Clamp: 이미지 가장자리의 1픽셀을 늘입니다.
Mirror: 이미지가 거울을 댄 것처럼 계속 반복되게 만듭니다.
Mirror Once: 이미지를 u축(x축), v축(y축)으로 각각 한 번씩 거울을 댄 것처럼 만듭니다.
Per-axis: u,v축 각각 적용할 효과를 정할 수 있습니다.
Per-axis 옵션을 선택하면 인스펙터 창에 다음과 같은 설정 레이아웃이 생깁니다.
상단의 이미지는 U 축에 repeat, V 축에 Clamp 를 적용한 상태입니다.
그렇다면 하단의 이미지는 각 축에 어떤 옵션을 적용한 것일까요?
U축에는 Clamp, V 축에는 Repeat 옵션을 적용했습니다.
이런 식으로 나무를 길어지게 만들 수도 있습니다.
Clamp 옵션을 사용했습니다. 나무의 기둥 부분의 맨 밑 픽셀들이 밑으로 더 늘어나면서 나무가 굉장히 길어진 것처럼 보이네요.
3. Time 노드
새로운 노드가 나왔습니다.
Time 노드 입니다.
이 노드는 '유니티가 켜진 시간'을 계속 세고 있습니다. 즉, 숫자가 계속해서 커진다는 의미입니다.
숫자가 계속 커진다는 것은, 이 숫자를 이용해서 뭔가를 '진행시킬 수 있다' 라는 것을 뜻합니다.
셰이더그래프를 다루면서, 이 Time 노드를 어떻게 사용할 수 있을까요.
만약 한 텍스쳐가 흘러가는 것 처럼 만든다면, Time 노드를 '텍스쳐 UV를 지속적으로 움직이게 해서, 흘러가는 것처럼 보이게 만드는'식으로 활용할 수 있지 않을까요?
직접 노드로 만들어보겠습니다.
UV를 움직이게 하는 것은 add 노드이니, 더해주는 수에 Time 노드를 넣겠습니다.
잘 움직입니다.
그런데, 여기서 움직이는 속도를 제어하고 싶어진다면 어떻게 할까요.
이럴 때는 속도를 0.1배/1배/2배/4배 이런 식으로 제어하기 위해, 속도에 일정 값을 곱해줍니다.
multiply 노드를 사용하는 것입니다.
아래 노드와 같이 만들어주세요.
Time multiply 라는 변수는 값에 따른 변화를 확인해보기 쉽게 property로 빼줍니다.
제대로 작동합니다.
여기서 Time multiply 를 음수로 만들어주면,
반대쪽으로 움직입니다.
그리고, 곱해주는 값을 0으로 만들면
움직이지 않게 됩니다.
UV의 이동하는 값에 0을 곱해주면, 이동하는게 0이 되므로 결국 이동하지 않는다는 것이 되기 때문입니다.
물론 위에서 add, multiply, time multiply를 해줬던 것들을 u,v축 각각 다른 수를 적용해줄 수도 있습니다.
또한 r,g,b,a에 각각 다른 변수를 적용할 수도 있습니다.
예시로 만들어 본 것입니다.
예시를 multiply로 들었지만, 만약 Add 를 사용해서 r,g,b 각각에 다른 값을 주었다면 chromatic aberration 같은 느낌을 내 줄 수도 있습니다.
4. 굴절시키기
움직임의 값을 직접 UV에 줄 수 있다고 하면, 그 값 또한 텍스쳐로 똑같이 표현할 수 있다는 것을 유추해볼 수 있습니다.
우선 0부터 1까지의 값을 텍스쳐로 표현해주고, 그 강도는 multiply 를 이용해서 조절해 줍니다.
간단하게 노드를 만들었습니다.
기본 텍스쳐는 간단한 원형 그라데이션 텍스쳐를 활용했습니다.
그 결과 텍스쳐가 왜곡되면서 이동하는 결과가 나왔습니다.
가운데로 갈수록 왜곡이 심해지도록 만들어진 텍스쳐이므로 (가운데로 갈수록 1에 가까워짐) 위와 같은 모습이 나오게 됩니다.
똑같은 원리로 저곳에 적당한 노이즈 텍스쳐를 넣어준다면 예쁜 굴절 효과가 나타나게 됩니다.
몇 가지 기능을 가진 노드를 직접 만들어봅시다. 조건은 아래와 같습니다.
먼저 완성된 모습입니다.
-
원하는 원본 텍스쳐와 노이즈 텍스쳐를 넣을 수 있도록 만들기
-
원본 텍스쳐의 UV는 계속해서 이동
-
원본 텍스쳐는 노이즈 텍스쳐의 값(0~1)에 따라 uv가 이동하는 속도가 달라짐 (굴절되는 것처럼 보임)
-
원본 텍스쳐의 크기(타일링)을 조절할 수 있어야 함
-
노이즈 텍스쳐의 크기(타일링)을 조절할 수 있어야 함
-
uv의 이동 속도 조절가능하도록 만들기
-
노이즈의 강도를 조절가능하도록 만들기
노이즈의 강도는 time노드에 노이즈 텍스쳐를 곱한 것처럼, 다른 수를 곱해주는 노드를 똑같이 추가해주면 조절할 수 있습니다.
5. 불 이펙트 만들기
위에서 배운 간단한 기능들을 이용해서 불 이펙트를 만들어보겠습니다.
먼저 최종 완성 모습입니다.
아래 두 가지 이미지를 사용했습니다. (스터디에서 받은 이미지입니다)
왼쪽부터 각각 1번 이미지/2번 이미지라고 부르겠습니다.
1. 1번 이미지가 위로 올라가면서 이동하도록 만듭니다. 속도 조절을 할 수 있어야 합니다.
2. 최종적으로 나타나는 색은 1번과 2번을 add시키고, emission이 나올 수 있도록 해야 합니다.
3. 알파는 두 이미지의 알파를 적절히 합해서 만들어야 합니다.
1. 1번 이미지가 위로 올라가면서 이동하도록 만듭니다. 속도 조절을 할 수 있어야 합니다.
- 상/하로만 움직이니 V축, 즉 G값만 움직이게 하면 됩니다. split 노드를 이용해서 G값만 따로 빼주고, time에 속도 조절을 위한 vector1을 곱한 것을 add 해준다음, combine노드를 이용해서 원래 UV의 R값과 합쳐줍니다. 그것을 1번 이미지의 UV에 연결해줍니다.
2. 최종적으로 나타나는 색은 1번과 2번을 add시키고, emission이 나올 수 있도록 해야 합니다.
- 설명 그대로 만들어줍니다.
3. 알파는 두 이미지의 알파를 적절히 합해서 만들어야 합니다.
- 합한다고 해서 add라고 헷갈리실 수도 있지만 multiply를 이용해서 만들어야, 1번 이미지의 알파 가장자리가 이동하면서 불이 움직이는 것 같은 효과가 납니다.
추가로 unlit master 노드에 있는 AlphaClip Threshold 를 이용하면 가장자리를 깨끗하게 잘라서 카툰 그래픽 풍의 불을 만들어 볼 수도 있습니다.
저 같은 경우엔 Sine Time의 절댓값(absolute)을 이용해서 불의 윗부분이 조금씩 변화되도록 만들어보았습니다. (이미지 2의 알파 윗부분이 고정되어 있고, 그라데이션처럼 부드럽게 사라지기 때문에 AlphaClip Threshold를 사용하면 적당하겠다고 생각했기 때문입니다. 다만 너무 규칙적으로 커졌다 작아졌다를 반복하고 있는게 보이는건 마음에 안드네요.)
추가로 Posterize 노드를 써서 1번 이미지의 색상을 단순화시켰습니다.
6. 디테일 맵 만들기
디테일 맵이란?
말 그대로 디테일을 추가해주는 맵을 말합니다.
예를 들어서 1인칭 게임에서, 이런 바닥 텍스쳐가 화면상에서 매우 크게 보인다고 했을때,
플레이어가 바닥을 보면 이미지가 이렇게 매우 확대되어 보일 것입니다.
이를 해결하기 위한 것이 디테일 맵입니다.
아래 이미지는 제가 직접 포토샵에서 high pass 필터를 이용해 보정한 이미지입니다.
(여기서 high pass란 고주파를 의미하는 것으로, 이미지에 있어서는 음영이 급격하게 변할수록 높은 주파수라고 부릅니다.)
이 이미지를 아까 배운 UV Tiling 을 이용해서 위에 multiply 해주면,
이렇게 위에 디테일이 올라갑니다.
위 이미지는 타일링 값이 10 정도 되는데, 만약 저 해상도를 유지하기 위해 생 이미지를 통채로 써야 했다면 이미지 용량이 매우 커질 것입니다. 정말 비효율적이겠죠.
이런 식으로 간단하게 만들 수 있습니다.
노말맵 등을 이용해서, 캐릭터의 피부 표현을 하는데에도 사용되곤 합니다.
디테일 맵 적용 전
디테일 맵 적용 후
피부 모공 표현 (출처: 유니티 매뉴얼)
캐릭터의 모공 표현이 매우 디테일하게 들어가있는 것을 볼 수 있습니다.
추가로 해보기
1. 스크린 스페이스 UV
위에서 텍스쳐 공간에 대응하는 버텍스의 UV에 대해서 설명했습니다.
이와 비슷하게 스크린 스페이스(스크린 포지션이라고도 합니다) UV라는 것이 존재합니다.
위에서 계속 다뤘던 UV와는 다르게, 스크린 스페이스 UV는 말 그대로 스크린, 즉 우리가 화면상으로 볼 수 있는 출력 결과물의 2D 좌표상의 공간을 의미합니다.
유니티 씬 화면에 오브젝트 하나가 가득 차도록 둔 뒤, 스크린 스페이스를 표현해주는 셰이더를 적용해보았습니다.
화면 전체를 하나의 2D 좌표 공간으로 보고, (0,0) 부터 (1,1) 까지 표현하고 있습니다.
'화면'이 기준이기 때문에, 보이는 창을 줄이면 공간이 똑같이 정규화돼서 변하는 것을 볼 수 있습니다.
이것 역시 UV, 즉 2D좌표 공간이기 때문에 위에서 계속 했던 것과 같이 노드를 연결해주면 똑같이 굴절시킬 수 있습니다.
위 스크린 포지션 노드는 다음과 같이 꺼낼 수 있습니다.
2. 스크린 컬러
스크린 기반의 UV도 가져올 수 있는데, 아예 스크린에 출력된 결과물 자체를 가져올 수도 있지 않을까요?
당연히 가능합니다.
이를 이용해서 물 같은 곳에 많이 쓰이는 화면 굴절 셰이더를 만들 수 있습니다.
https://chulin28ho.tistory.com/555 를 참고했습니다.
카메라에서 가져오기
먼저 카메라에서 렌더링한 결과물을 셰이더그래프 안으로 가져올 수 있도록 해야합니다.
블랙보드에 Texture2D를 하나 생성해주고,
Reference에 다음과 같이 입력해줍니다.
카메라에서 출력되는 불투명한 렌더 결과물을 레퍼런스로 가져오겠다는 의미입니다.
(비슷하게 Depth Texture라는 것도 존재하는데, 실험 결과 잘 불러와집니다.)
그 다음 ,
사진과 같이 스크린 포지션을 UV로 해서 마스터 노드에 컬러로 연결하면,
이렇게 뭔가 블러되면서 이상해집니다.
*
이 문제는 간단하게 해결할 수 있지만, 이 부분이 왜 이렇게 되는지에 대해서 궁금해졌기 때문에 조금 고민해보았는데요. 설명을 찾을 수가 없었어서(뭐라고 찾아봐야 할지조차 몰랐습니다ㅠㅠ) 그냥 직접 추론해보았습니다.
블러되는 과정이 안티앨리어싱을 엄청 반복하는 것 같다는 느낌에서부터 시작했습니다. (이건 정확하지 않습니다. _CameraOpaqueTexture을 가져올 때 무슨 일이 일어나는지 모르기 때문에...ㅠㅠ 다만 오브젝트를 움직여서 씬을 업데이트 시킬때마다 프레임단위로 점점 블러되었기 때문에 추론해본 것 뿐입니다.)
그렇기 때문에 카메라가 찍은걸 가져오는 순서에 문제가 있어서 이렇게 되는 게 아닐까 싶었습니다. 위 gif의 plane 오브젝트가 있는 씬을 찍고 또 찍고.. 그걸 반복해서 나타나는 결과물인 것 같다는 느낌이 강했기 때문입니다. 이런걸 흔히 뇌피셜이라고 하나요. 정확하지 않았지만 일단 한번 저 가설을 밀고 가 보았습니다.
그렇다면 Camera Opaque Texture를 가져오고 나서, 그 위에 저 plane 오브젝트를 렌더하면 되지 않을까? 싶었고, 많이 들어봤던 렌더큐 라는 단어를 생각해냈습니다. 엔진 기초 수업때 유니티 렌더과정을 봤던 것도 있고, 뭔가 느낌상 렌더 순서를 의미하는 것 같아서 (참고했던 블로그 글에서도 한번 언급되었고요.) 찾아보니 실제로 렌더 순서를 의미하는게 맞았습니다.
저는 블로그 글을 읽으면서 미리 한번 만들어봤기 때문에 transparent로 언릿 마스터 노드 세팅을 변경하면 문제가 해결된다는 것을 알고 있었습니다. 여기서 렌더 큐를 transparent로 바꾸니 언릿 마스터에서 바꾼 것과 동일하게 문제가 해결되었습니다.
그렇다면 과연 렌더 큐 몇까지가 블러되지 않은 채로 유지되는 걸까? 라는 궁금증에서.. 적당히 숫자를 줄여나가다, 2500에 들어가면 다시 블러가 시작되는 것을 발견하고, 검색해보니 렌더 큐 2500가 마지막 opaque요소인 스카이박스가 렌더되는 순서라는 얘기를 바로 찾았습니다.
가설이 틀렸더라도 일단 렌더 순서때문에 일어나는 것이라는 건 맞았다는 걸 알게 되었고.. 너무 재밌었습니다. 역시 공부는 이런 맛으로 하는 거네요.
*
간단하게 언릿 마스터 노드의 surface를 transparent로 바꿔주면 해결됩니다.
+ 그렇다면 현재 만들어둔 transparent 세팅의 셰이더들이 서로 겹치면, 앞에 있는 것만 나오게 되는데 이건 어떻게 해결해야 할까요?? _CameraOpaqueTexture 을 써서 가져오면 Opaque단계까지 렌더링한걸 가져온다는 의미같은데.... ㅠㅠㅠ 제가 뭔가 잘못하고 있는걸까요???
3. 디스토션 셰이더
그 뒤는 앞에서 했던 것과 같이, 노이즈를 이용해서 만들어줍니다.
앞에서 했던 것들과 원리는 완벽하게 같습니다.
아래 노드에서는 저는 추가로 gradient noise라는 노드를 사용해보았습니다.
그러면 간단하게 디스토션 셰이더 완성입니다.
이걸 바닥에 두면 이렇게 간단한 수영장이 만들어집니다.
(노드 마지막에 살짝 푸른색을 곱해주었습니다.)
4. 배운 것 다 합쳐보기
공부하다가 '예쁜 걸 만들고 싶다' 라는 생각이 들어서.. 의식의 흐름대로 만들어본 개인작입니다.
개인적으로 이렇게 자신이 만들고 싶은 걸 만들다보면 공부도 많이 되고 좋은 것 같네요.
*저 테두리가 생기면서 사라지는 쉐이더는 나중에 스터디에서 해보는 걸로 알고있는데, 그냥 '이렇게 하면 될거같은데' 라는 느낌이 들어서 만들어버렸습니다....
전체 노드입니다.
- 우주 텍스쳐는 스크린 포지션 기반 UV를 적용했고, 살짝씩 디스토션을 줘서 공간이 비틀린 느낌을 표현하려고 해보았습니다.
- 위에 써둔 굴절 기능을 사용했습니다.
- 프레넬 노드가 있길래.. 꺼내서 사용했습니다. 프레넬 연산 원리를 알아봐야겠네요.
- 알파를 적절히 사용해서 굴절 셰이더와 우주 셰이더가 번갈아가며 나오도록 만들어보았습니다.
시도해보고 싶은 게 많아서, 이번 게시물은 내용이 스터디에서 진행했던 것과는 많이 멀어진 것 같은 느낌이 있네요.
뭔가 많이 해봤는데도 아직 궁금한 게 많이 남아있습니다. 예를들어서 UV오프셋을 이용해서 얼굴 커스터마이징을 하는 기능을 만들어보고 싶은데, 여러가지 이미지 중에서 하나를 고를 수 있도록 하려면 어떻게 해야 하는지 등등(찾아보니까 flipbook이라는 게 있던데, 원리를 이해를 못하겠어서 일단 아직 적지는 않았습니다..) 1개를 공부하면 알고싶은게 2개 생길 정도로 궁금한게 굉장히 많이 생기고 있습니다.. 언젠가 직접 블로그에 설명글을 쓸 수 있게 되면 좋겠네요.
'대학교 공부' 카테고리의 다른 글
[엔진심화] 01. 프리팹(Prefab)과 FBX (0) | 2021.03.29 |
---|---|
2학년 1학기 카라렌 과제 - 3ds max scanline 렌더러로 재질 만들기 (0) | 2021.03.15 |
4. 버텍스 컬러와 활용 (0) | 2021.03.15 |
02. 유니티 셰이더그래프 (1) | 2021.03.15 |
01. 색상 표현 기본원리, 색 연산 기초 (2) | 2021.03.15 |