본문 바로가기

유니티 쉐이더 스타트업

[ 유니티 쉐이더 스타트업 ] 05 - 2 . Surface Shader를 활용한 텍스쳐 제어

[ 텍스쳐 한장만 출력하는 쉐이더 만들기]

[ 불필요한 코드 지우기 ]

새로운 Surface Shader를 생성한다 .

_Color / _Methalic / _Glossiness와 기타 주석 , 전처리기등을 지운 텍스쳐만을 출력하는 코드이다 .

위 코드는 앞으로 하게될 작업의 기본적인 코드가 될 것이다 .


 

[ 텍스쳐 출력 살펴보기 ]

1 . Properties

_MainText ("Alvedo (RGB)",2D)="White"{}

텍스쳐를 입력받는 인터페이스를 만드는 곳이다 . 각 부분을 자세히 뜯어보자면

  • _MainTex : 텍스쳐를 입력받는 변수
  • "Albedo (RGB)" : 이 부분은 Albedo 텍스쳐를 넣는 곳이고 , 알파를 제외한 RGB 채널만 사용한다는 의미이다 .
  • 2D : 해당 인터페이스가 2D 텍스쳐를 입력 받는 부분임을 의미한다 .
  • "White"{} : 해당 텍스쳐 인터페이스가 처음 생겼을때 , 흰색 택스쳐가 들어 있다 생각하고 만듬을 의미한다 .

2 . 변수

sampler2D _MainTex;

 

위의 인터페이스에서 받는 텍스쳐는 다음의 sampler로 받는다. 

이때 , 텍스쳐는 uv와 만나 UV좌표와 함께 계산되어 출력되기전까지 메모리에 올라와 있는 텍스쳐일 뿐이다.

 

UV와 만나 계산되어야 색상(float4)로 표현할 수 있다 .

따라서 현재 텍스쳐는 float4 _MainTex가 아닌 sampler2D로 선언한다 .

 

3 . Input 구조체

float2 uv_MainTex;

UV는 vertex가 가지고 있다. 직접 만든 인터페이스가 아닌 vertex 내부에 있는것을 

엔진에게 내놓으라 명령할때는 Input 구조체 안에 넣어야 한다 .

 

해당 구조체에는 임의의 변수를 넣을 수 없고 , 정해진 규칙대로 작성해야 한다 .

uv는 u와v 2개의 숫자로 이루어져 있으므로 float2이고 , _MainTex의 uv라는 뜻으로

uv_MainTex처럼 sampler이름 앞에 uv라는 글자를 붙인다 .

 

4 . surf 함수

   void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

surf 함수 내부에 텍스쳐를 연산하는 함수인 tex2D를 이용하여 텍스쳐의 컬러를 화면에 출력한다 .

 

여기서 fixed4는 float4보다 훨씬 작은 크기단위이다 . float은 하나에 32비트 영역을 가지는데 컬러를 담기에는 너무 크다 .

float의 1/2인 half (16비트) 혹은  fixed (11비트)가 필요에 따라 쓰인다 .

게임에 사용되는 대부분의 텍스쳐 컬러는 채널당 8비트 이하이므로 fixed로도 충분하기에 fixed를 사용한다.

 

이때 , uv_MainTex는 In put구조체 IN에 들어가 있기에 IN.uv_MainTex라 사용함을 주의하자 .

 

 

프로퍼티에 텍스쳐를 넣어보자

다음과 같이 출력됨을 볼 수 있다 .

 


 

[ 이미지 흑백으로 만들기 ]

[ 흑백처리 ]

새로운 Surface Shader를 생성한다 .

그림자 관련된 구문인 fullforwardshadows를 삭제해준다 .

해당 구문이 있다면 , 해당 쉐이더를 사용한 오브젝트는 포워드 렌더링 상태일때 ,

모든 라이트에게서 그림자를 생성한다. 

 

삭제시 가장 가벼운 라이트인 디텍셔널 라이트에게서만 그림자를 생성, 포인트/스폿 라이트는 그림자를 생성 안한다 .

 

surf 함수의 Albedo를 다음과 같이 작성한다 .

흑백이미지는 두가지 속성을 가지고 있는데 

  • RGB모두 동일한 숫자로 이루어져 있다 .
  • RGB 각 요소에 따른 강도의 평균이다 .

위를 생각하면 코드를 이해 할 수 있을 것이다 .

위 방식은 기본적이고 간단한 GrayScale 구현 방식이다 .

다음과 같이 흑백 이미지가 출력된다 . 


[ RGB to YIQ 변환 매트릭스 ]

 RGB to YIQ 변환 매트릭스를 활용한 다음의 공식도 가능하다 .

GrayScale= 0.2989 * R + 0.5870 * G + 0.1140* B

RGB 이미지를 Grayscale로 변환하는 함수 만들기.

 

【Project】RGB 이미지를 Grayscale로 변환하는 함수 만들기.

음성처리와 함께 영상처리실습 프로젝트 중 하나였던 RGB 이미지를 Grayscale로 변환하는 함수 구현에 대한 내용입니다. 이는 영상 전처리(Pre-Processing)에 해당하는 기본적인 내용이어서, 사실 MATLAB

oasiz.tistory.com


 

[ Lerp 함수 사용해보기 ]

[ Lerp ]

https://ko.wikipedia.org/wiki/%EC%84%A0%ED%98%95_%EB%B3%B4%EA%B0%84%EB%B2%95

직선적인 비율로 값이 변화되는 것을 의미한다 .

 

lerp(X,Y,S)

선형보간 (Lerp) 함수는 다음과 같이 사용된다 .

x,y는 같은 단위이어야 하고 , s는 float 이어야 한다 . s값이 0에 가까우면 X로 , s값이 1에 가까우면 Y로 출력된다 .


[ 사용해보기 ]

일단 텍스쳐 한장을 출력하는 쉐이더를 준비한다 .

Standard Asset (지금은 지원중단으로 새로 받을 수는 없다 . 전에 받았다면 여기서 받을 수 있다)

에 있는 풀 이미지를 넣어준다 .

해당 이미지는 알파채널을 가지고 있지만 , 아직 알파채널이 적용되는 쉐이더가

아니므로 해당 효과가 보여지지는 않는다 .

두개의 텍스쳐를 받을수 있게 인터페이스와 변수를 추가해준다 . 

두가지 이미지를 넣어준다.

serf 함수에서 Albedo를 받는 부분에 lerp 함수를 사용하자 . 현재 lerp의 마지막 값은 0이다 . 

첫번째 텍스쳐가 출력된다 .

1이라면?

두번째 텍스쳐가 출력된다 .

lerp의 마지막 값을 받는 프로퍼티를 생성해서 유니티에서 직접 조절이 가능하다 .

반반 출력이 됨을 볼 수 있다 .

 


[ 알파채널 적용하기 ]

첫번째 이미지에는 다음과 같이 알파채널이 포함되어 있다 .

검은색은 0 흰색은 1이다 . 중간에 보이는 회색은 0.5 이다 .

그렇다면 상단 lerp의 인자를 해당 이미지의 알파채널로 넣으면 어떨까?

위와 같이 적용해보자 .

위와 같이 적용된다 . 즉 검정 부분은 0이기에 c 이미지에 가깝게 나오고 흰색 부분은 1이기에 d 이미지에

가깝게 나온다 . 이는 두가지 방식으로 해결이 가능하다 .

1 . d와 c의 위치를 바꾼다

1에서 빼준다 .

이러한 결과물을 볼 수 있다 .