셰이더를 활용해본 경험이 있을까요? 어떻게 활용했는지 설명해주세요.
셰이더(Shader)
- 3D 모델의 정점 위치를 계산하거나 최종 색상을 결정하는데 영향을 주는 프로그램
= 렌더링 되는 오브젝트의 최종적인 시각적인 형태를 결정
셰이더의 활용
BillboardShader 활용
- 맵은 3D 오브젝트를, 플레이어는 2D 스프라이트를 사용하는 게임 개발에서 카메라 방향에 따른 스프라이트 왜곡을 방지하기 위해 Billboard 셰이더를 활용
Shader "Custom/Billboard"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
// billboard 중심 위치
float3 center = float3(0, 0, 0);
// 현재 월드 공간에서 카메라 방향
float3 camRight = UNITY_MATRIX_V._m00_m01_m02;
float3 camUp = UNITY_MATRIX_V._m10_m11_m12;
// 빌보드 오프셋
float3 worldPos = center + v.vertex.x * camRight + v.vertex.y * camUp;
// 클립 공간으로 변환
o.vertex = UnityObjectToClipPos(float4(worldPos, 1));
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return tex2D(_MainTex, i.uv);
}
ENDHLSL
}
}
}
- 현재 월드 공간에서의 카메라 위치에 따른 스프라이트 회전을 통해 빌보드를 구현
#pragma vertex vert // vert 함수가 정점 셰이더 프로그램임을 컴파일러에 지시
#pragma fragment frag // frag 함수가 프래그먼트(픽셀) 셰이더 프로그램임을 컴파일러에 지시
- 해당 셰이더가 렌더 파이프라인에서 어떤 단계에 사용되어야하는지 명시
- 이 셰이더는 버텍스 셰이더와 프래그먼트 셰이더를 처리하는 단계에서 사용됨
// 빌보드 오프셋 계산:
// 원래 모델의 정점 위치 (v.vertex)를 사용하여 빌보드 중심(center)으로부터의 상대적인 오프셋을 계산
// v.vertex.x * camRight: 원래 모델의 x축 방향 오프셋을 카메라의 월드 공간 오른쪽 방향으로 변환
// v.vertex.y * camUp: 원래 모델의 y축 방향 오프셋을 카메라의 월드 공간 위쪽 방향으로 변환
// 이렇게 하면 모델의 각 정점은 카메라의 오른쪽과 위쪽 방향을 기준으로 배치되어 항상 카메라를 바라봄
float3 worldPos = center + v.vertex.x * camRight + v.vertex.y * camUp; // 최종 월드 공간 위치
- 카메라 위치에 따른 정점 위치를 재배치에 항상 카메라를 바라보도록 함