유니티에서 셰이더는 스크립트를 만들 때와 비슷하게, 프로젝트 뷰에서 우클릭-Create-Shader 하단에서 선택하여 제작할 수 있다.
이 중, 당분간 사용할 셰이더는 Standard Surface Shader, Unlit Shader이다. 직역하면 표준 표면 셰이더와 라이팅을 사용하지 않는 셰이더다 뭘로 만들어도 관계는 없으나, 일단은 Unlit Shader로 생성해보자. 아래는 Unlit Shader의 이름을 HelloWorld로 제작한 결과
Shader "Unlit/HelloWorld"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
뭔가 대문에 사용한 이미지와 거의 차이가 없어 보이는데, 라이팅이 적용되지 않고 순수하게 텍스쳐만 적용되어 미묘하게 밝아진 걸 알 수 있다.
아래와 같이 수정해주자
Pass
{
Material
{
Diffuse (1,1,1,1)
Ambient (1,1,1,1)
}
Lighting On
SetTexture[_MainTex] {
constantColor (1,1,1,1)
Combine texture * primary DOUBLE, texture * constant
}
}
전체 소스코드에서, 방금 추가한 코드 부분을 제외한 나머지 부분을 살펴보자
Shader "Custom/HelloWorld"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// ...
}
}
Shader라는 커다란 블록 안에 Properties와 SubShader 블록이 들어가 있다.
Shader 블록은 HTML로 치면, <html></html>에 해당한다. 셰이더의 시작과 끝을 지정해주며, 하나의 셰이더에 단 하나의 Shader 블록만 존재한다.
Shader "Custom/HelloWorld"
{
// ...
}
그리고 Shader 오른쪽에 있는 "Custom/HelloWorld"는 셰이더의 이름이에요. 스크립트와 달리, 셰이더는 파일 명이 아닌, 여기서의 명칭이 인스펙터에 표기된다.
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
프로퍼티는 외부로부터 받아올 값을 선언해주면 돼요. 여기서는 텍스쳐 한 장 받아오는 걸로 선언해두었다.
변수 선언은 아래 형식이 기본형이다
변수명 ("인스펙터에 보여줄 이름", 자료형) = 기본값
즉
변수명 = _MainTex
인스펙터에 보이는 이름 = Texture
자료형 = 2D
기본값 = white {}
여기서, 인스펙터에 보이는 이름은 스크립트 상에서 displayName으로 명명된다. 통상 Material.Set~~~함수에 집어넣는 이름은 변수 명인 _MainTex가 된다.
자료형 2D는 2D 텍스쳐를 의미한다 기본값 white {}는 아무런 텍스쳐도 집어넣지 않았으면 흰색으로 꽉 채운 텍스쳐를 적용한다는 의미가 되겠다
SubShader
{
// ...
}
SubShader에는 아까의 예제에서 체험했듯이, 셰이더의 실제 동작이 들어간다. 그런데 왜 이름이 SubShader일까?
의문이 들었으니 한 번 수정해보자
Shader "Custom/HelloWorld"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
Pass
{
Material
{
Diffuse (1,1,1,1)
Ambient (1,1,1,1)
}
Lighting On
SetTexture[_MainTex] {
constantColor (1,1,1,1)
Combine texture * primary DOUBLE, texture * constant
}
}
}
최초 제공되었던 코드에서 SubShader 블록만 걷어낸 코드다
실행 결과, 마젠타 색상을 뱉으면서 뻗어버린다
유니티에서는 셰이더에 문제가 있으면 이렇게 마젠타 색상으로 도배되며 에러 코드를 반환한다.
그럼 SubShader가 반드시 있어야 하는 거라는 의미인데, 얘가 뭔데 필수조건일까?
사실, SubShader는 하나의 셰이더에 여러 개가 들어갈 수 있다.
Shader "Custom/HelloWorld"
{
SubShader
{
// ..
}
SubShader
{
// ..
}
SubShader
{
// ..
}
}
SubShader는 대상이 되는 컴퓨터 환경에 맞춰서, 최고급 품질의 셰이더부터 최하급 셰이더까지 작성된다. 유니티에서 실제 런타임에서 사용할 SubShader를 고를 때, 셰이더 사용 가능 여부를 위에서부터 검증하기 때문에, 위에서부터 아래로 갈수록 점점 낮은 품질에 대한 셰이더를 지원해주면 된다
하지만 우리가 짜둔 모든 SubShader가 모든 디바이스에 맞으리라는 보장은 없다. 그래서 유니티에서는 다른 셰이더를 호출해, 모든 SubShader가 통과되지 않은 환경을 고려할 수 있게 해준다.
Fallback을 말로 풀면 이렇다.
위에 있는 모든 SubShader를 못 쓰는 환경이라면, "Diffuse" 셰이더를 찾아서 실행해라.
여기서 Diffuse는 유니티의 Legacy Shader 중 Diffuse 셰이더를 의미한다.
Shader "Custom/HelloWorld"
{
SubShader
{
// 최고급 품질의 셰이더
}
SubShader
{
// 적당한 품질의 셰이더
}
SubShader
{
// 최하급 품질의 셰이더
}
}
마지막으로, SubShader 안에 있던 코드 중 Pass만 알아보자
Pass는 유니티에서 오브젝트를 렌더링 하는 사이클을 의미한다. 하나의 SubShader에는 여러 개의 Pass가 들어갈 수 있으며, 여러 개의 Pass가 구성된 SubShader는 렌더링 과정을 Pass 단위로 수행한다.
Pass가 여러 개 적용되는 가장 대표적인 케이스로는, 한 점에 2개 이상의 광원이 적용되는 경우를 들 수 있는데 메인이 되는 광원을 이용해 일단 기본 색상을 렌더링 해주고(ForwardBase Pass), 여기에 추가되는 광원으로 인한 색상 변화를 계산하여 덧입혀주면(ForwardAdd Pass) 여러 광원에 의한 효과를 적용할 수 있다. 이게 Forward 방식 렌더링의 기본이다
이외에도 그림자를 추가로 드리우는 데 사용하거나, 아웃라인을 그려주거나, 아예 다른 렌더링 기법을 적용하는 데 사용하거나, 굉장히 여러 이유로 SubShader에 여러 개의 Pass를 적용한 셰이더가 개발된다.
Shader "Custom/HelloWorld"
{
SubShader
{
Pass
{
// ...
}
}
}
'게임엔진 > Unity' 카테고리의 다른 글
[Unity] 그래픽스 퍼포먼스 최적화 (1) | 2024.04.18 |
---|---|
[Unity] 모바일 빌드 방법 (IL2CPP, MONO) (0) | 2024.04.08 |
[Unity] DOTS: Jobs, Burst, ECS 간단 정리 (0) | 2024.01.04 |
[Unity] ThreadPool (스레드풀) (0) | 2024.01.03 |
[Unity] MVC, MVP, MVVM 디자인 패턴 (0) | 2023.10.19 |