본문 바로가기

Graphics

타일별로 크기 조절이 되는 셰이더 만들기

(유니티 빌트인 렌더 파이프라인 - Vertex&Fragment 셰이더 사용 / 언리얼 메테리얼 사용)

 

개요

'텍스처를 타일링해 반복시키고, 반복된 각각의 텍스처가 그대로 크기 조절이 되도록' 만드는 방법이 있는지 친구에게 질문을 받았습니다. UV만 조금 건드리면 될 것 같은데... 먼저 어떻게 만들어야 하는지 러프하게 생각해봅니다. 👀

 


 

대략적인 동작 방식 그리기

Tiling 텍스처 그래프와 타일링된 모습 (x : UV * Tiling, y : 텍스처 좌표)

 

일반적으로 텍스처가 타일링 될 때의 그래프는 위 이미지의 왼쪽과 같습니다.
UV에 Tiling값으로 3이 곱해져, UV가 0~1일 때 텍스처가 하나(0~1, 텍스처의 좌표), 1~2일 때 텍스처가 하나, 마지막으로 2~3일 때 텍스처가 하나 반복되는 식입니다. (UV 및 텍스처 좌표 x, y는 편의를 위해 통칭함)
그렇게 Tiling 값에 따라 반복된 텍스처는, 이미지 오른쪽 부분과 같은 모습으로 메시상에 표시됩니다.

여기서 목표하는 방식으로 다가가려면, 아래 이미지와 같이 타일링된 그리드는 그대로 유지되면서, 각각의 타일들이 별개로 크기가 조절되어야 합니다.

(텍스처의 반복 방식이 clamp일 때, Tiling 값으로 텍스처를 축소/확대하기도 하나, 이번 글에서는 편의를 위해 'Tiling : 텍스처가 반복되는 값', 'Scale : 각각의 타일의 크기를 조절하는 값'으로 나누어 부르겠습니다.)

 

목표하는 방식의 그래프 및 모습 예

 

우선 텍스처가 반복되도록 타일링을 넣어 줍니다. 그 다음, 각각의 타일에 Scale 값을 곱해 그래프의 기울기를 증가(원의 크기를 줄임)시킨 뒤, Scale 값에 따라 타일링이 되지 않도록 최종 값을 제한해주면 목표한 느낌으로 될 것 같아요.

 


 

frac()으로 타일링한 뒤 saturate()로 크기를 조절 시에 더 반복되지 않게 하기

윗 단락에서 대략적으로 이야기했던 대로 만들어 보겠습니다. 다만, 최종적으로 saturate()를 통해 최종 UV값이 0~1 사이를 넘거나 내려가지 못하도록 제한할 것이기 때문에, frac()을 통해서 UV를 먼저 0~1 사이로 만들어 줍니다.

그래프로 나타낸다면 아래와 같은 모습이 되겠습니다.

 

Tiling 된 값에 frac()을 적용한 그래프

 

그 다음에는 0~1 사이의 타일 값들에 Scale 값을 곱해 한번 더 크기를 조절해줍니다.
그래프로 나타낸다면 아래 이미지의 왼쪽 모습처럼 될 것입니다.

하지만, 이렇게 된다면 타일링된 텍스처를 한번 더 타일링하게 되겠죠. 이를 막기 위해 오른쪽 그래프와 같이 saturate()를 통해 값이 1을 넘지 않도록 제한해줍니다. 그러면 타일링되는 수는 유지되면서, 텍스처의 크기만 줄어들 것입니다.

 

Scale 값을 추가로 곱한 그래프(좌)와 해당 값을 saturate()를 통해 제한한 그래프(우)

 

···

float _Tiling;
float _Scale;
float _OffsetX;
float _OffsetY;

fixed4 frag (v2f i) : SV_Target
{
    float2 uv = saturate(frac(i.uv * _Tiling) * _Scale);

    fixed4 col = tex2D(_MainTex, uv);

    return col;
}

···

 

유니티 셰이더 코드로 나타낸다면 위와 같이 작성할 수 있습니다.
Tiling 값에 따라 텍스처가 반복되고, Scale 값에 따라서는 텍스처의 크기가 조절되는 모습을 볼 수 있습니다.

 

Tiling과 Scale값이 별개로 동작하는 모습

 


 

중앙 기준으로 타일링과 크기 조절이 이루어지도록 수정하기

윗 단락의 최종 결과물로 마무리를 짓기에는 뭔가 부족합니다. 목표하던 아름다운 모습으로 만드려면 타일링과 크기 조절이 각 텍스처의 중앙 (텍스처 기준 0.5, 0.5) 기준으로 이루어지도록 해야겠죠.

기준점을 옮겨주는 김에, Offset 값도 추가해보겠습니다.

 

···

float _Tiling;
float _Scale;
float _OffsetX;
float _OffsetY;

fixed4 frag (v2f i) : SV_Target
{
    float2 offset = float2(_OffsetX, _OffsetY);
    float2 uv = saturate((frac((i.uv - 0.5) * _Tiling + 0.5 + offset) - 0.5) * _Scale + 0.5);
    // 중앙 기준으로 타일링 / 크기 조절되도록 수정 + Offset 값 추가

    fixed4 col = tex2D(_MainTex, uv);

    return col;
}

···

 

중앙 기준으로 값이 적용되고, Offset도 적용된 모습

 

첫 목표에 맞게, 중앙 기준으로 아름답게 적용되는 모습을 확인할 수 있습니다.
방금 만든 유니티 셰이더를 언리얼 메테리얼 노드로도 만들어 본다면, 아래와 같은 형태로 구성하게 되겠습니다.

 

언리얼 메테리얼 노드 구조

 

언리얼 메테리얼 동작 예

 


 

이번에는 텍스처가 타일링되고, 각각의 타일에서 개별적으로 크기가 조절되도록 셰이더를 만들어보았는데,
다음번엔 오늘 만든 셰이더에 기능을 더해보는 것도 재밌을 것 같습니다. 😋

 

유니티 셰이더 코드 전문은 아래 링크에서 확인하실 수 있습니다.

 

GitHub - rkato0128/ShaderStudy_Unity

Contribute to rkato0128/ShaderStudy_Unity development by creating an account on GitHub.

github.com

 

 

 

'Graphics' 카테고리의 다른 글

색상 간의 혼합 - 기초 블렌딩 연산  (0) 2023.10.09
SDF (Signed Distance Field)  (0) 2023.09.17
색체계와 색의 구성요소  (0) 2023.07.15
디지털 색상과 수  (0) 2023.06.25
왜곡 셰이더 만들기  (0) 2023.05.15