본문 바로가기

Graphics

왜곡 셰이더 만들기

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

 

개요

렌즈 왜곡처럼 중앙을 기준으로 방사형으로 왜곡이 적용되는 셰이더를 만들면 연출에 잘 사용할 수 있을 것 같아, 기대하면서 왜곡 셰이더 만들기를 시작했습니다.

 


 

첫 시도

처음에는 UV값을 텍스처를 통해 증감시키기만 하면, 방사형으로 왜곡될 것이라고 생각했었습니다.
UV 좌표 0.5, 0.5를 기준으로 1사분면의 UV엔 텍스처 값을 더해 1시반 방향으로 움직이고, 3사분면의 UV에선 텍스처 값을 빼 7시 반 방향으로 이동하는 식으로요.

그렇게 만들어보니, 렌즈 왜곡이라고 하기에는 묘한 결과물이 나왔습니다.

 

4분면으로 나눈 뒤 텍스처 값으로 UV에 증감연산을 한 결과

 


 

distance() 를 사용해 왜곡 적용하기

렌즈 왜곡처럼 원형으로 왜곡을 적용하려면 어떻게 해야할까 고민하던 중에, distance() 가 생각났습니다. 중앙을 기준으로 UV에 distance 값을 잘 적용하면 만들어질 것 같아 일단 키보드를 두드리기 시작했습니다.

그러던 도중, UV 자체가 0,0 에서 시작하는 벡터라는 개념이 다시 떠올랐습니다.
벡터(UV)에 스칼라(distance)를 곱할 때 벡터의 방향은 그대로고 벡터의 크기만 바뀌니, 벡터의 시작점을 텍스처의 중앙(UV 0.5, 0.5) 로 보정한 뒤 중앙 기준의 distance 값을 곱연산하면 원형으로 왜곡이 적용될 것입니다.

 

벡터와 스칼라의 곱

 

첫 시도에서는 곱연산 대신에 증감연산을 사용해서 마름모 꼴로 왜곡되었던 것이었구나 라는 작은 깨달음을 얻고, UV에 distance 값을 곱해 원하던 방사형 왜곡을 만들어내는데 성공했습니다.

 

uv 에 distance 값을 곱해 원형으로 왜곡이 적용되는 모습

 

왜곡 효과를 조금 더 다이나믹하게 넣고 싶은데 어떻게 하면 좋을까 하며 다른 분들은 어떻게 만들었을까 찾아보았습니다. 아래 Shadertoy 코드에서는 distance 값에 pow() 를 적용해서 왜곡 효과를 과장시키더라고요. 바로 pow() 도 추가했습니다.

 

 

Shadertoy

 

www.shadertoy.com

 

pow() 를 추가해 강조되는 왜곡 효과의 모습

 

···

fixed4 col;

float2 uv1 = (i.uv - 0.5) * _Tiling;
float dis = distance(float2(0, 0), uv1) * _Tiling;
// 텍스처 중앙점(원래값 0.5, 0.5)에서 거리 계산

float2 distortedUV = uv1 * pow(dis, _Power);
// pow 적용해 왜곡 강도 조정
uv1 += 0.5;
distortedUV += 0.5;
// UV 이동

float2 finalUV = lerp(uv1, distortedUV, _Value);

return col = tex2D(_MainTex, finalUV);

···

 

distance()를 통해 원형으로 왜곡 효과를 적용하는 부분의 코드입니다.
텍스처의 중앙 (0.5, 0.5) 을 기준으로 distance()를 통해 거리를 계산하고, 계산한 거리 값을 pow()를 통해 제곱한 뒤 텍스처의 UV로 사용해서 왜곡 효과를 적용했습니다.

 


 

텍스처를 사용해 왜곡 적용하기

distance를 사용한 왜곡 효과를 만들고 나서 든 생각은, 첫 시도에서 곱연산을 사용했다면 텍스처를 사용해서도 왜곡 효과를 만들 수 있었겠구나 였습니다.

그리고, 텍스처를 사용하는 게 더 나을 것 같습니다. 아무래도 미리 정의된 텍스처 값을 사용하는게 distance로 매 픽셀마다 거리 계산을 하는 것 보단 값도 싸고, 다른 도형 형태로 왜곡할 때에도 연산을 통해 셰이더에서 도형을 만들어내는 것보다 텍스처로 해당 도형을 정의하는 게 더 간편하기도 하고요.

텍스처를 사용한 왜곡 효과도 만들어 봅시다.

 

텍스처를 사용해 왜곡을 적용한 모습 (좌 : 원 / 우 : 별 모양)

 

···

fixed4 col;

float2 uv2 = (i.uv - 0.5) * _Tiling;

fixed4 distortionTex = tex2D(_DistortionTex, (i.uv - 0.5) * _DisTexTiling + 0.5); // 왜곡용 텍스처

float2 disTexUV = uv2 * pow(distortionTex.r, _Power) + 0.5;
uv2 += 0.5;
// pow 적용해 왜곡 강도 조정, UV 이동

float2 finalTexUV = lerp(uv2, disTexUV, _Value);

return col = tex2D(_MainTex, finalTexUV);

···

 

언리얼 메테리얼 노드로는 아래와 같은 모양으로 구성하게 되겠습니다.
(위의 유니티 셰이더 코드와 다르게, 왜곡 적용 방향을 반전시키기 위해 왜곡용 텍스처 옆에 1-x 노드를 추가했습니다.)

 

언리얼 메테리얼 노드 구조

 

왜곡 메테리얼 동작 예

 


 

하나 만들어두면 두고두고 쓸 만한 왜곡 효과를 만들어보았습니다.
수학의 중요성을 다시금 와닿게 만들어준 작업이 아니었나 싶네요... 😂

최종적으로는 왜곡의 적용 방향 반전 옵션도 토글로 추가해서 작업을 완료했습니다.

 

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

 

 

GitHub - rkato0128/ShaderStudy_Unity

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

github.com