Unity Surface Shader 기초 4강 - SurfaceOutputStandard 활용하기

유니티에서 기본 마테리얼을 만들면 위 사진과 같이 기본 쉐이더가 작성된것을 확인 할 수 있다.

PBR 기반으로 다수의 텍스처를 활용하는 쉐이더이며 이는 기본 Surface Shader에서 

SurfaceOutputStandard 구조체에서도 비슷한 내용을 확인 할 수 있다.

이전 포스팅에서는 쉐이더 기본 활용을 목적으로 당장 결과물을 보이기 위해 Albedo나 Emission을 사용 했지만

이번 포스팅에서는 Normal부터 시작하여 여러 옵션들을 활용한 쉐이더를 만들어 보고자 한다.

 

 

Normal Map

노말맵은 렌더링될 물체의 픽셀마다 표면반사의 높낮이가 있어 보이게 하여 울퉁불퉁하게 보이게하는 것이다.

다른 말로 범프 맵(Bump map)이라고 한다.

 

노말맵이 파란색계열인 이유는 노말맵핑하는데에 있어서 2개의 채널(R,G)밖에 사용하지 않고 B는 항상 1값이 되어있어서 그렇다.

그래서 벽 텍스처 한 개로 표현하는 아래의 담장이 

 

위와 같이 노멀맵을 이용하여 더 입체감있게 보이게 할 수 있다.

 

이번엔 이전 처럼 새로 Surface Shader를 만들어서 노멀맵을 적용할 수 있는 쉐이더를 만들어 보자

Properties
{
  _MainTex("Albedo_1 (RGB)", 2D) = "white" {}
  _BumpTex("Normal Map", 2D) = "bump" {}
}

먼저 일반적인 텍스처 2개를 받을 수 있는 인터페이스를 작성한다.

sampler2D _MainTex;
sampler2D _BumpTex;

struct Input
{
  float2 uv_MainTex;
  float2 uv_BumpTex;
};

SubShader구문 안에 인터페이스를 받을 변수와 Input에 uv변수를 똑같이 작성한다.

 

  void surf (Input IN, inout SurfaceOutputStandard o)
  {
      fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
      float3 n = UnpackNormal(tex2D(_BumpTex, IN.uv_BumpTex));

      o.Albedo = c.rgb;
      o.Normal = n;
  }

실제로 쉐이더 출력하는 부분의 코드이다.

Albedo맵은 똑같이 출력하지만 노멀맵에는 한 가지 함수 사용해야 되는 과정이 있다.

UnpackNormal ()함수를 통해서 텍스처 값을 뽑아서 o.Normal로 출력하고 있다.

 

UnpackNormal()은 간단하게 노말맵에 사용할 수 있게 변환하는 함수이다.

자세한 내용이 추후 세부 이론 포스팅에 작성하겠다.

좌측의 색을 가진 노멀맵을 UnpackNormal()함수를 통해 우측처럼 만들어야 정상적인 동작이 가능하다.

 

이로서 노멀맵이 적용된 쉐이더가 완성이 되었고 위 사진은 비교 사진이다.

 

추가적으로 노멀맵이란 쉽게 말해서 빛이 오는 방향을 반사시킬 방향이다.

만약 반사되는 빛이 강해지면 이론상 더 노멀맵이 더 잘 보이게 될것이다. 

 

Smoothness

Smoothness는 표면의 거칠기를 제어한다. 거친 재질은 부드러운 재질보다 좀 더 난반사를 강하게 만든다.

값이 1에 가까울 수록 표면이 부드러워져 거울처럼되고 0에 가까울 수록 사포처럼 반사가 없는 재질로 변한다.

 

이전 Normal Map설명 마지막에 말했던 것 처럼 난반사가 강해지면 얼마나 노멀맵이 강해지는지 확인해보자

 

o.Smoothness = 0.7f;

 

Metallic

Metallic은 표면이 얼마나 금속같은지를 결정하는 값이다. 

일반 적으로 순수한 금속인 경우 1값이고 그 외의 경우는 0이다. 중간값은 물리적으로 존재할 수가 없지만

먼지 혹은 녹이 낀 금속 혼합일 경우에는 중간 값이 필요 할 수 도 있다.

 

 

Occlusion(Ambient Occlusion)

환경광(간접광)을 차폐하는 값이다. 현실적으로 균열, 주름 같은 것은 환경광의 영향을 많이 받지 않는다.

이 현상을 게임에서 구현하기 위해 존재하는 Occlusion값이다.

 

기본적으로 1값이면 환경광에 영향 받고 0값이면 영향 받지 않는다.

 

 

실습 쉐이더 제작 - Normal Map을 이용하여 물 쉐이더 만들기

이전 포스팅에서 만들었던 버텍스 컬러를 이용항 텍스처 마스크 자료에다 

Normal Map과 Smoothness를 이용하여 물이 흐르는 쉐이더를 만들어 보자.

 

우선 노멀맵을 받을 수 있게 인터페이스를 만들고 아래 출력할 수 있도록 구현을 하자.

하지만

텍스처를 1개더 받을 수 있게 만들고 컴파일을 하면 에러가 뜬다.

에러의 주 내용은 현재 Forward Base pass에서 너무 많은 텍스처를 사용 해서 에러가 뜬다는 것이다.

코드 내에 #pragma target 3.0 을 추가하여 해결 할 수 있다.

이 코드는 쉐이더 컴파일 타겟 레벨을 변경한다는 뜻이며 최신 타겟 레벨일 수록 기능이 많아 진다.

참고자료 : https://docs.unity3d.com/kr/2018.1/Manual/SL-ShaderCompileTargets.html

 

  fixed4 c_1 = tex2D(_MainTex_1, IN.uv_MainTex_1);
  fixed4 c_2 = tex2D(_MainTex_2, IN.uv_MainTex_2);
  fixed4 c_3 = tex2D(_MainTex_3, IN.uv_MainTex_3);
  fixed4 c_4 = tex2D(_MainTex_4, IN.uv_MainTex_4);

o.Albedo = c_1.rgb;

o.Albedo = lerp(o.Albedo, c_2, IN.color.r);
o.Albedo = lerp(o.Albedo, c_3, IN.color.g);
o.Albedo = lerp(o.Albedo, c_4, IN.color.b);

float3 n = UnpackNormal(tex2D(_BumpTex, IN.uv_BumpTex + _Time.y / 20.0f));
o.Normal = n;

위 코드로 노멀맵을 추가하고 물 노멀 텍스처를 추가한 사진이다.

코드상에 특이점은 UnpackNormal 함수에 노멀맵 UV에 _Time변수로 맵이 흐르는 효과를 주었다.

 

위 사진 상에 노멀맵현상이 잘 보이지 않는다. 이를 해결하기 위해 난반사를 강하게 하여 물 노멀이 더 잘 보이게 해보자.

o.Smoothness = 0.7f;

Smoothness 값을 0.7로 하니 노멀이 훨씬 강조되어 물처럼 보이게 되었다.

 

이제 강줄기 흐르는 것을 표현하기 위해 위 버텍스 컬러의 가운데 B값에만 물 노멀맵이 흐르게 해야한다.

 

float3 n = UnpackNormal(tex2D(_BumpTex, IN.uv_BumpTex + _Time.y / 20.0f));
n.r *= IN.color.b;
n.g *= IN.color.b;
o.Normal = n;

o.Smoothness = 0.7f * IN.color.b;

위 코드드에서 버텍스 컬러의 B채널 값만 곱셈 공식에 집어 넣어 계산 상으로 위 버텍스 컬러 사진상에 파란 부분 외에는 0값이 들어오므로 결과적으로 파란 부분만 노멀이 출력되고 Smoothness가 적용 되는 것을 확인 할 수있다.

 

 

 

 

 


WRITTEN BY
CatDarkGame
Technical Artist dhwlgn12@gmail.com

,