炸殺
카테고리
작성일
2020. 5. 9. 17:33
작성자
炸殺

버텍스에는 다양한 정보가 들어있습니다.

 

대표적으로 

1. Index

2. Position

3. UV

4. Normal

5. Color

 

등이 있죠. 이 5개만 알고 있어도 어디가서 욕먹지는 않을 겁니다.

오늘 저희가 오늘 주목할 건 이 5개의 정보들 중 'Color'입니다. 

 

버텍스에는 float4의 '색'을 자체적으로 가지고 있습니다. RGBA 알파까지! 공짜로요!

텍스쳐를 따로 넣지 않아도 컬러를 넣을 수 있다는 말입니다.

 

공짜!

 

버텍스 컬러를 따로 건들이지 않았을 땐 기본적으로 float4( 1, 1, 1, 1 )로 되어있습니다. 흰색의 불투명.

즉 우리가 버텍스 컬러를 사용하지 않아도 버텍스 컬러의 정보는 어찌됐건 포함이 되어있는 겁니다.

 

사용을 안할 이유가 없겠죠.

 

 

 

 

자 그래서 버텍스 컬러를 어떻게 넣냐,

 

3D MAX에서 넣는 방법이 있고 유니티 자체에서도 넣을 수가 있는데요,

우선 3D MAX에서 버텍스 컬러를 넣어봅시다.

 

 

 

 

 

 

 

 

Vertex Color 넣기 - 3D MAX

 

 

가장먼저 사용할 오브젝트를 만들어준 뒤 Convert To>Convert to Editable Ploy를 눌러줍니다.

(폴리곤이 많을 수록 섬세한 표현이 가능하다)

그럼 오른쪽의 Modify창이 활성화 되는데요,

 

Selection의 가장 첫번째에 위치한 점 3개!

Vertex를 선택해주면 오브젝트에 파란 점들이 생기며 버텍스를 '선택'할 수 있게 됩니다.

드레그를 통해 색칠하고 싶은 영역을 선택해봅시다.

 

선택된 버택스는 빨간색으로 바뀐다.

 

이 상태로 Selection에 Vertex를 선택한 채로 쭉 내리다 보면 Vertex Properties라는 칸이 있을 겁니다.

 

와! Edit Vertex Color! 기본적으로 불투명한 흰색 float4(1,1,1,1)이 들어가 있는 걸 확인 할 수 있습니다.

색상이 바뀌길 원하는 버택스를 선택해준 뒤 Color를 조정해 주면....!

 

아무 일도 일어나지 않았습니다.

 

왜 아무 일도 일어나지 않는 걸까요?

Vertex Color는 기본적으로 '안보이는 것'이 정상입니다.

그렇기 때문에 지금까지 우리가 Vertex Color의 존재를 간과한걸지도 모릅니다. 안보이니까!

 

Vertex Color를 보기 위해선 다른건 됐고! 버텍스 컬러 보여줘! 하고 따로 명령을 해줘야합니다.

 

내놔!

 

방법은 간단합니다.

오브젝트 우클릭 후 Object Prorerties를 클릭하면 다음과 같은 창이 뜨는데요.

 

이거 누르면
이 창이 뜹니다.

빨간색 네모박스로 표시된 Vertex Channel Display로 체크해 준 뒤 OK를 눌러주면.....

 

 

와!

아까 지정했던 버텍스 컬러가 보입니다! 기본이 하얀색이기 때문에 칠하지 않은 부분은 흰색으로 되어있네요. 

Vertex Channel Display를 체크하게되면 적용된 텍스쳐, 메터리얼을 모두 무시하고 Vertex Color를 보여줍니다.

(다시 텍스쳐나 머터리얼을 보고싶다면 끄도록하자!)

 

 

 

하지만 버텍스를 하나하나 선택해 칠하기에는.....너무 힘이들죠......이걸 언제 다 하나하나 클릭하고 있어요......

라고 생각하는 여러분들을 위한 또다른 한 가지 방법을 소개합니다.

 

 

 

 

바로 >>Vertex Paint<<!!

 

 

 

 

오브젝트를 새로 생성하여 Convert To>Convert to Editable Ploy 까지 다시 해줍시다.

 

 

다음으로 상단의 Modifier List를 클릭하여 Vertex Paint를 찾아 선택해줍니다.

(철자를 그대로 적는게 아니라 계속 V(앞글자)를 누르다 보면 나온다.)

 

Vertex Paint Bar

그럼 이런 창이 뿅하고 뜨는데요.

붓! 지우개! 컬러!

핵심 기능들을 살펴보면 예상하셨듯이

영문 설명이 있는 건 생략ㅎ

 

다음과 같은 기능을 가지고 있습니다. 와! 그럼 브러쉬를 누르고 원하는 컬러로 칠하면 되겠네요! 

 

 

안됩니다.

 

이번에도 역시 Vertex Color가 보이도록 '명령'해주어야하는데요,

위에서 설명했던 방식대로 해도 되지만 Vertex Paint를 사용할 경우 더 간단한 방법으로 볼 수 있습니다.

 

 

무지개 박스

바로 요 두 친구 중 하나를 눌러주면 됩니다! 각 박스의 기능은 다음과 같습니다.

 

Vertex Channel Display - unshaded
어떠한 연산 없이 Vertex Color만을 표시합니다. Emission같은 느낌.
Vertex Channel Display - shaded
빛/그림자가 있을 경우 Vertex Color와 함께 연산하여 표시합니다. Albedo같은 느낌.
Disable vertex color display
3D MAX에서 기본적으로 보여주는 음영 모드를 표시합니다.
적용한 텍스쳐, 메테리얼 그림자 등등... 
Toggle texture display on/off
현재 선택한 개체의 텍스쳐 맵을 표시하거나 숨깁니다.

자세한 내용은 메뉴얼 참고 -https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2019/ENU/3DSMax-Modifiers/files/GUID-C6746472-B239-45F1-B8F0-38420ACD7399-htm.html

 

 

 

 

내가 칠한 버텍스 컬러가 표시 됐다!

 

만약 Object Prorerties에서 이미 Vertex Channel Display를 체크한 상태라면

VertexPaint를 실행했을 때 처음부터 Vertex Channel Display - unshaded가 선택되어있는 상태로 바가 생성됩니다.

 

 

Vertex Paint가 좋은 이유가 한 가지 더 있습니다.

바로 손쉽게 레이어 추가, 삭제, 합치기가 가능합니다. 만약 버텍스 컬러도 주고 버텍스 알파도 주고 싶다?! 하신다면

Vertex Alpha 레이어를 추가해줍시다! (알파는 하나의 채널(float)을 가지고 있기 때문에 검정색과 흰색으로 칠해주자)

 

자신이 선택한 레이어가 어떤 속성을 가지고 있는지는 오른쪽 Modify에서 확인하실 수 있습니다.

 

나중에 Collapse해도 버텍스 컬러 정보는 Diffuse 남아있다.

 

 

이제 유니티로 가봅시다.

 

 

 

 

 

 

 

Vertex Color 넣기 - Unity

 

 

 

원래 유니티에서는 없던 기능이었지만 생겼습니다.

때문에 본격적으로 색을 넣어보기에 앞서 Window > Package Manager에서 Ploybrush를 Install해줍시다

 

신세계가 열리는 문

 

인스톨이 완료되었다면 Tools > Polybrush > Polybrush Window를 클릭하여 툴창을 열어줍니다.

 

 

Ploybrush Window

 

 

 

 

 

 

 

https://unity3d.com/kr/unity/features/worldbuilding/polybrush

 

PolyBrush의 주요 기능으로는

메시 조형(Vertex의 Position 조작), 텍스쳐와 컬러블렌드, 버텍스 컬러 페인트, 오브 젝트 분산 배치 등이 있지만

이번 포스트에서 중점으로 다룰 건 '버텍스 컬러 페인트' 기능입니다.

 

 

 

세번째 세모를 클릭하자!

 

위에서 설명했던 3D MAX의 Vertex Painter의 핵심 기능과 비슷합니다.

Outer Radius는 최대 직경, Inner Radius는 최소 직경, Strength는 강도를 조절 할 수 있습니다. 

가장 아래 보이는 Color Mask에서 원하는 컬러로 설정한 뒤 칠해주면...!

 

안됩니다.

네 맞습니다. 유니티에서도 Vertex Color를 보기 위해선 Vertex Color를 보여달라고 요청해야합니다.

저 노란 세모 경고창을 보면 Vertex Color를 볼 수 있는 메테리얼이 없다고 말해주고 있어요.

 

지금부터 Unity에게 Vertex Color 좀 보여달라고 말하러 가보도록합시다.

 

Standard Surface Shader를 생성한 뒤 정리해주었다.

Vertex Color는 버텍스 안에 존재하는 정보입니다.

 

버텍스 안에 들어있는 정보.....? 익숙한 문장이죠.

지난번 포스트에서도 버텍스 안에 들어있는 정보인 UV를 꺼내왔었습니다. (기억이 안나신다구요? 여기를 클릭하세요.)

 

 

Vertex Color역시 UV와 마찬가지로 엔진에서 가져와야하는 정보이기 때문에

struct Input에 입력하여 받아와 주어야 합니다.

 

 

Vertex Color는 알파까지 포함한 float4의 값을 가지고 있습니다.

그 다음 이어지는 이름은 보편적으로 color를 사용하지만 원하는 이름으로 정해줄 수 있습니다. 바꿔도 상관 없어요.

 

 

 

저희가 주목해야할 부분은 바로 :COLOR 입니다.

세미콜론(;)은 수도 없이 많이 사용하였지만 콜론(:)은 생소한데요, 이것을 시맨틱(Semantics)이라고 부릅니다.

 

 

사전적으로 '의미론', '의미'라는 뜻을 가지고 있으며,

말 그대로 해당 변수의 정확한 '의미'를 GPU에게 알려주는 테그와 같은 역할을 합니다.

쉐이더의 인풋 구조체들이 어떤 자료와 연결 될지 알려주는 것이 바로 이 시맨틱인 것이죠.

참고 자료 : https://docs.microsoft.com/ko-kr/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics?redirectedfrom=MSDN

 

사실 UV를 받아올 땐 뒤에 :TEXCOORD를 적어줘야하는데.....

하지만 Standard Surface Shader에서는 이 시맨틱이 많이 축약되어있습니다.

굳이 시맨틱을 안달아줘도 되게 말이죠. (근데 어째서인지 칼라는 남았다)

 

 

하지만 Surface Shader가 아닌 Fragment Shader에서는 이렇게 시맨틱을 이용한 형태의 변수들을 사용합니다.

 

 

 

잠깐 주제와 벗어나지만 하나만 짚고 넘어가자!

원래 UV를 불러오기 위해선 :TEXCOORD를 적어줘야되는 것도 알겠는데,

뒤에 [n]은 뭐고, UV는 분명 float2인데 왜 Type이 float4로 되어있을까요?

 

float4 TEXCOORD;
float2 UV;

UV = TEXCOORD.xy

즉 uv는 float4 Texcoord의 xy를 가져온 샘입니다. 그렇다면 uv2는? Texcoord.zw를 사용하여 가져올수 있겠죠.

 

 

그럼 뒤에 붙어있는 [n]은 무엇일까요?

이건 Texcoord0, Texcoord1처럼 '숫자'를 붙일 수 있다는 의미입니다.

보통 Texcoord0은 uv1, uv2로 쓰이지만,

Texcoord1부터는 '그냥 float4짜리 변수'로 취급해서 uv를 더 넣어줘도 되고 심지어 컬러를 넣을 수도 있습니다.

(가끔 넣어준다고...)

 

Particle System의 Custom Vertex Streams. 저 괄호 안에 있던게 바로 시멘틱이었다.

 

 

다시 본론으로 돌아와서...

이제 Vertex Color도 받아왔으니 두 눈으로 확인해봐야겠죠.

UV를 불러왔을 때와 마찬가지로 Vertex Color를 꺼내옵시다.

 

 

Vertex Color 고유색을 보기 위해 Emission으로 불러왔다.

 

마구잡이로 그렸던 Vertex Color가 드러났다.

 

이렇게 그려진 Vertex Color를 텍스쳐에 곱해준다면?

파릇파릇한 텍스쳐
를 곱해주면
짜잔!

 

 

마치 포토샵의 곱하기 레이어를 씌운 것처럼 자연스럽게 색상이 얹어졌습니다.

이를 이용하면 단조롭게 반복되는 텍스쳐에 불규칙한 변수를 더해주어 자연스러운 연출도 가능하겠네요! 

 

[왼쪽: 쌩 텍스쳐] [오른쪽: 버텍스 컬러를 곱해줌]

 

 

 

 

 

 

 

Texture Splatting

 

계속해서 반복해서 말하고 있지만 컬러는 곧 숫자라는 것을 자연스럽게 떠올리셔야합니다.

Vertex Color는 버텍스가 공짜로 주는 '색상' 보다

Vertex Color는 버텍스로 공짜로 주는 'float4'로 생각하는 순간 갑자기 할 수 있는 것들이 막 생각나실 겁니다.

 

 

출처 - 유니티 공식 블로그

 

잠시 Terrain의 이야기를 해봅시다.

넓은 지형을 만들 때 널리 쓰이는 Terrain은 지형을 만들고, 텍스쳐를 섞거나 오브젝트를 분산 배치 하는데 용이하지만

너무 무겁다는 단점과 함께 부유섬, 동굴, 밑부분이 더 깎여있는 절벽 등을 만들 수 없고 부분적으로 버텍스 밀도를 조절할 수 없다는 단점이 있습니다.

 

지금 부터 저희가 할 건 Vertex Color를 이용해 Texture Splatting을 해보는 겁니다! 

Ploy brush의 매시 조형 기능을 사용한다면 지형의 높낮이도 표현할 수 있고 아니 이럴 수가 오브젝트 분산 배치 기능도 있습니다. 그래요! 우리가 Terrain을 직접 만드는 겁니다!

 

 

Paint texture on Mesh를 선택하니 경고창이 떴다.

텍스쳐 블렌드 기능 역시 있지만 텍스쳐 블렌드 쉐이더를 따로 짜줘야합니다. 지금은 Vertex Color를 이용해봅시다.

 

 

 

가장 먼저 할건 Vertex Color를 모두 '검정색'으로 칠해주는 것.

알파를 제외하면 (1,1,1)의 값을 이미 가지고 있기 때문에 (0,0,0)으로 초기화 해주는 겁니다.

(완벽한 검정색이 아닌 이유는 GI때문. Emission이여도 약간의 연산은 들어간다. Directional Light를 꺼주면 깨끗한 검정색을 볼 수 있다.)

 

 

이제 각 채널의 값을 마스킹 레이어로써 사용하는 겁니다.

포토샵으로 생각한다면 각각의 채널이

포토샵의 레이어 마스크

이 친구의 역할을 수행하는 겁니다. 그래요....포토샵은 쉐이더.......

 

r 채널만 출력했다.

RGB도 R따로 G따로 B따로 보면 1과 0. 흑백으로 표시 되잖아요?

저희가 수도 없이 사용했던 레이어 마스크는.....float이었던 겁니다................쟤 흑백만 되잖아요....이유가 있었던 거임....

 

때문에 노란색, 마젠타처럼 2채널 이상 1의 값을 가지고 있는 색상이 아닌 빨강, 초록, 파랑으로 칠해줍시다.

 

 

 

 

그럼 이제 마스킹할 텍스쳐를 불러 올 수 있도록  Properties를 생성해주어야겠죠.

배경 레이어에 들어갈 거 하나,

R에 마스킹할 거 하나,

G에 마스킹할 거 하나,

B에 마스킹할 거 하나.

해서 총 4개의 텍스쳐를 불러올 수 있도록 만들어줍시다.

텍스쳐 4개를 불러올 수 있다!

위의 코드 상태에서는 나머지 칸에도 텍스쳐를 불러와도 Baxe Tex에 넣은 텍스쳐만 표시가 될 것입니다.

 

그럼 어떻게 해야 Vertex Color의 RGB채널을 이용해 마스킹 할 수 있을까요?

우리는 이전 포스트에서 이미 마스킹을 해봤습니다. 기억 안나신다고요...? 네.... 여기를 클릭해주세요.....

 

 

float!

각각의 채널도 float. Lerp함수의 중간값 역할을 하는 s값도 float! 이 점을 이용해 텍스쳐를 블랜딩 해봅시다!

 

lerp(텍스쳐1, 텍스쳐2, 마스킹 채널)
Rtex에 넣었던 텍스쳐가 표시 되었다.

 

Vertex Color를 빨갛게 칠해준 영역만큼 두번째 텍스쳐가 표시되었습니다!

lerp를 좀 더 간단하게 생각하면

lerp(이 텍스쳐를 바탕으로, 이 텍스쳐를, 얘가 가진 값만큼 표시하겠습니다)

입니다.

 

 

 

이제 이어서 G와 B채널에도 텍스쳐를 마스킹해봅시다.

 

각각 RGB채널에 해당하는 텍스쳐가 마스킹 되었다.

나머지 텍스쳐 들도 각각 초록색과 파란색을 칠해주었던 영역만큼 마스킹이 되었습니다.

 

 

하지만 여기서 한가지 의문점이 듭니다.

o.Emission을 저렇게 많이 사용해도 되나? 중복해서 사용했는데 오류가 왜 안나지?

 

 

코딩은 오른쪽부터 읽고 위에서부터 아래로 읽습니다.

 

가장 아래 적힌 친구가 절대적이죠.

예를 들어서 40번째 줄float3 A = float3(1,0,0);이라고 변수 선언을 하고,

그 아래 41번째 줄 A = A + float3(0,1,0); 라고 작성한하면

42번째 줄o.Emission = A; 로 출력했을 때 빨간색이 아닌 노란색이 나오게 됩니다.

즉,

A와 B를 섞고 A와 B를 섞은 거에 C를 섞고 A와 B를 섞은 거에 C를 섞은 거에 D를 섞은 것을 출렸했다.

 

물론 이것보다 더 복잡하게 짤 수도, 더 명료하게 짤 수도 있습니다. lerp를 사용하지 않고 마스킹을 할 수도 있습니다.

 

 

 

 

 

 

 

 

 

Normal map, Smoothness

 

 

 

텍스쳐만 있으면 아무래도 밋밋합니다. Normal map과 Smoothness를 넣어봅시다.

노말....이 친구는 무진장 특이한 녀석입니다. 뭔가....특별한...그런....

 

너무 길어져서 조금 정리해줬다

 

위에서 부터 차근차근 알아봅시다.

 

 

bump

Properties를 만드는 건 지금까지 텍스쳐를 불러왔던 방법과 같습니다. 단 기본 값을 'bump'로 넣어줍시다.

white를 넣는다고 해서 에러가 나거나 그런 것은 아니지만 Normal에 흰색이 들어갈 경우엔 빛 연산은 이상하게 받을 수가 있습니다. 어차피 텍스쳐를 넣어주면 없어질 값이지만 Normal 텍스쳐를 넣기 전까지 이상하게 연산되고 있음 작업에 차질이 생길 수도 있으니깐요.

 

 

#pragma target 3.0

사실 이 친구는 이전까지 지워도 상관 없었습니다. 지워도 쉐이더가 정상적으로 잘 작동했죠.

하지만 지금 부터 지우면 에러가 납니다. 바로 Shader 2.0의 한계에 도달한 것.

 

이 친구를 지울 경우 기본으로 OpenGL ES 2.0으로 작동을 하게 되는데,

이 버전은 인터폴레이터를 최대 8개까지만 지원합니다.

현재 이미 텍스쳐를 4개나 사용하고 있는 상황에서 노말맵까지 추가를 못하는 겁니다. 능력오버!

 

때문에 CGPROGRAM을 시작하면서 #pragma target 3.0을 선언함으로써 더 최신 버전을 사용하겠다 말하는 것.

대신 이걸 사용하면 구버전의 기기에선 돌아가지 않습니다. 구버전이라고 해도 갤럭시3 정도지만.

현재 #pragma target 3.0를 사용하지 않는 곳은 없다라고 생각해도 될 정도로 범용적으로 사용되고 있지만

중국이나 동남아쪽의 시장을 생각한다면 완전히 배제할 수는 없는 상황입니다. 물론 이거보다 더 높은 버전도 있습니다.

 

메뉴얼에서도 최소한으로 사용하길 권장하고 있다.

 

 

sampler 2D와 uv, tex2D 변수 선언은 이전과 같으니 넘어가고~~

지금까지와 하나 더 다른 것이 바로 Normal을 출력할 때의 선언입니다.

 

 

 

 

UnpackNormal

Albedo와 Emission의 경우엔 별도의 함수 없이 알맞는 변수명만 가져와도 결과를 출력해 주었습니다. 

하지만 Normal은 따로 전용 함수를 붙여줘야합니다.

그냥 변수명만 입력하면 오류는 나지 않지만 제대로 출력이 되지 않습니다.

그냥 까맣게 되어버렸다.

 

 

 

 

그렇게 적용한 Normal map은...

 

적용이 되긴 했는데... 뭔가 약하다.

 

모든 물체는 적던 많던 스펙큘러(Speculer)를 가지고 있습니다.

특정 물체에 '질감'을 결정짓는 것이 바로 이 Speculer인데 Speculer가 없기 때문에 뭔가 어색해 보이는 것.

Normal map은 Speculer가 없으면 잘 느껴지지 않습니다.

 

그럼 Speculer도 연산해달라고 요청합시다!

유니티에선 Speculer를 Smoothness라는 이름으로 부릅니다.

 

SurfaceOutputStandard에 선언되어있다.

 

Normal이 더 잘 보인다!

Normal이 좀 더 선명해짐과 동시에 '젖은' 느낌이 나는 이유는

물체가 물에 젖었을 때 Speculer의 비율이 더 높아지기 때문입니다. 

 

 

Normal을 출력하는 방법은 몇가지 더 있는데,

변수를 먼저 선언한 뒤 노말을 불러온다면 노말의 '강도'를 조절하는 것이 가능해집니다.

 

 

UnpackNormal함수를 사용하기 위해선 반드시 float3여야한다.
Normal이 강해졌다!

 

각각 R과 G채널에 20을 곱해주었더니 노말이 강력해졌습니다. 

여기서 주의할 점은 R과 G채널만 건들여주어야 한다는 것. B채널을 건들이게 되면 에러가 발생됩니다.

왜 그런지에 대해서 설명하면 엄청 길어지기 때문에 따로 포스트를 작성하도록 하겠습니다.

 

 

 

 

 

 

 

 

 

 

응용

 

 

여기서부턴 위의 내용들과 지난 포스트에 대한 응용시간.

 

Normal강도와 Smoothness를 조절할 수 있게 됐다!

 

 

Smoothness와, Normal역시 마스킹이 가능합니다.

 

 

0에 1을 곱해봤자 0이기 때문에 1의 값을 가지고 있는 부분만 값이 변하는 원리!

현재는 B채널에만 Smoothness가 들어갔는데. lerp도 사용해봅시다.

 

 

따로 따로 Smoothness를 조절할 수 있게 되었다!

노말 역시 마스킹 되어있는 것을 확인할 수 있습니다!

움짤엔 없지만 노말 강도를 조절 할 블럭 부분의 노말만 조절이 됩니다.

 

 

 

 

전체 Smoothness와 Normal 마스킹