Ronja 님의 허락을 받고 번역한 튜토리얼입니다. 원문은 위 링크에서 확인하실 수 있습니다.
몇몇 부분은 생략·추가하였습니다.
의역과 오역이 넘쳐날 수 있으니 편하게 봐주시고 잘못된 부분은 알려주시면 감사하겠습니다!
목차
- 개요
- 기초 설정
- 조정 가능한 타일링
- 월드 좌표에 기반한 텍스처 좌표
개요
오브젝트에 텍스처 좌표가 없거나, 여러 오브젝트의 텍스처를 정렬하고 싶을 때, 또는 자신만의 UV 좌표를 생성할 다른 이유가 있는 경우들이 있습니다. 이번 튜토리얼에서는 평면 매핑이라는 제일 간단하게 텍스처 좌표를 생성하는 방식에 대해 다뤄보려고 합니다.
이 글에선 간단한 텍스처 셰이더를 기반으로 구현하겠지만, 서피스 셰이더를 포함해 모든 셰이더에 평면 매핑을 사용할 수 있습니다.
기초 설정
자체적인 텍스처 좌표를 생성해줄 것이므로, 입력 구조체에서 UV좌표를 제거하는 것부터 시작합니다.
struct appdata{
float vertex : POSITION;
};
UV좌표는 이전처럼 버텍스 사이를 보간할수 있으므로 버텍스 셰이더에서 새 UV 를 계산해줍니다. 먼저 UV 좌표를 오브젝트 좌표의 x 및 z 값으로 설정할 수 있습니다. 이 정도로 충분히 모델링에 텍스처를 나타나게 만들 수 있습니다. 모델의 텍스처는 위에서 누른 것처럼 보여지게 됩니다.
v2f vert(appdata v){
v2f o;
o.position = UnityObjectToClipPos(v.vertex);
o.uv = v.vertex.xz;
return o;
}
조정 가능한 타일링
셰이더는 텍스처 스케일링을 고려하지 않았고, 지금처럼 텍스처가 객체와 함께 이동하고 회전하는 것을 원하지 않을 수도 있습니다. 이를 위해 텍스처 스케일링과 오프셋을 조정 가능하게 고치려면, TRANSFORM_TEX 매크로를 UV 좌표에 넣으면 됩니다.
v2f vert(appdata v){
v2f o;
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.vertex.xz, _MainTex);
return o;
}
월드 좌표계에 기반한 텍스처 좌표
오브젝트의 위치와 회전을 식 외부로 꺼내기 위해서, 우리는 월드좌표계의 버텍스 좌표값을 사용해야 합니다. (이전엔 오브젝트의 중심을 기준으로 하는 상대좌표를 사용했었습니다.) 월드 좌표를 계산하기 위해선, 오브젝트에 월드 행렬을 곱해주면 됩니다. (행렬 곱셈에 대해 다루진 않겠습니다.) 월드 위치를 얻은 뒤엔, 이를 통해 UV 좌표를 설정해주면 됩니다.
v2f vert(appdata v){
v2f o;
// 오브젝트를 렌더하기 위해 클립 공간에서 좌표값 계산
o.position = UnityObjectToClipPos(v.vertex);
// 월드 좌표계의 버텍스 위치 계산
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
// 텍스처의 타일링과 오프셋에 기반하도록 UV 변경
o.uv = TRANSFORM_TEX(worldPos.xz, _MainTex);
return o;
}
보이듯이 평면 매핑에는 크게 타일링되는 텍스처로만 동작이 가능하다는 점과, 옆면에선 텍스처가 늘어나는 몇가지 단점이 있습니다. 다만, 추후 튜토리얼에서 다룰 트라이플래너 매핑과 같은 고급 기법을 사용하면 이러한 단점을 완화할 수 있습니다.
Shader "Tutorial/008_Planar_Mapping"{
// 인스펙터에서 조작할 수 있게 값 표시
Properties{
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
}
SubShader{
// 메테리얼은 불투명하고 다른 불투명 모델들과 같은 시점에 렌더됩니다.
Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
Pass{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
// 텍스처와 텍스처의 트랜스폼
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
struct appdata{
float4 vertex : POSITION;
};
struct v2f{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v){
v2f o;
// 오브젝트를 렌더하기 위해 클립 공간에서 좌표값 계산
o.position = UnityObjectToClipPos(v.vertex);
// 월드 좌표계의 버텍스 위치 계산
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
// 텍스처의 타일링과 오프셋에 기반하도록 UV 변경
o.uv = TRANSFORM_TEX(worldPos.xz, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_TARGET{
// UV 좌표의 텍스처를 읽어옵니다.
fixed4 col = tex2D(_MainTex, i.uv);
// 텍스처 색상에 틴트 색상을 곱합니다.
col *= _Color;
return col;
}
ENDCG
}
}
FallBack "Standard" // FallBack 으로 다른 오브젝트에 그림자가 지도록 그림자 패스를 추가합니다.
}
'Graphics > Ronja's Unity Shader tutorials' 카테고리의 다른 글
트라이플래너 매핑 (Triplanar Mapping) (0) | 2024.07.08 |
---|---|
색상 보간 (0) | 2024.06.15 |
스프라이트 셰이더 (0) | 2024.03.03 |
기본 투명 셰이더 (0) | 2024.01.21 |
유니티 서피스 셰이더 기본 (0) | 2023.11.19 |