유니티 셰이더 기초 - UV / Texture / Time / SinTime

코드멍멍이(Joonieboy)·2022년 9월 24일
1
post-thumbnail

UV는 뭘까?


UV를 설명하는 글들은 정말로 많아요. 하지만, 항상 UV는 헷갈리는 것 같아요. 저와 비슷했던 사람들도 많아서 이제는 쉽게 UV를 이해했으면 좋겠어요. 간단하게 생각해 보는건 어떨까요?

  • UV는 U와 V다.
  • U = X 이고, V = Y이다
  • 좌표 (x, y)를 표시하는 것 처럼 (u, v)로 인식하자
  • 보통 (0, 0) ~ (1, 1)까지 사용한다
  • 보통 2차원 좌표로 사용한다.

이 정도만 알면, 기초 단계에서 헤매일 경우는 드물어요. 그러면 사각형의 도형이 있다고 생각 했을때, UV 좌표는 어떻게 보일까 생각해볼까요? 제가 이미지로도 가져왔어요 !!

언리얼의 경우, 이와 다르지만 유니티에서는 이렇게 정해놨어요. 이 정도만 알았다면, 유니티 기초에서 UV를 사용하는데 큰 지장이 없어요.

  • 좌측 하단 = (0, 0)
  • 우측 하단 = (1, 0)
  • 좌측 상단 = (0, 1)
  • 우측 상단 = (1, 1)

유니티 쉐이더 UV 제어하기


일단, 지금껏 했던것 처럼 셰이더 파일을 만들어주세요. 그리고 셰이더 파일에서 쓸모 없는 것들을 지워주세요. 저희는 텍스쳐만 사용할 예정이예요. 그러니 유니티에서 머테리얼 셰이더를 방금 만든 셰이더로 지정하고 텍스쳐를 넣어주세요. 제가 사용한 텍스쳐 이미지를 올려드리니, 필요하신 분들은 사용하셔도 된답니다.

셰이더 스크립트에서 UV가 어떻게 사용되는지 알기 위해서는 InputSurf 부분을 봐야 해요. float uv_MaintTex;로 변수를 지정하고, Surf에서 fixed4 c = tex2D (MainTex, IN.uv_MainTex); 이렇게 사용이 되었어요.

struct Input
        {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Emission = c.rgb;
            o.Alpha = c.a;
		}

여기서 우리는 간단하게 Emission을 만져볼거예요. 원래는 Albedo로 돼있는데, 빛을 받지 않게 하기 위해서 Emission을 사용하였어요 !! 그러면 이 코드를 약간 손을 봐 볼까요? o.Emission의 내용을 o.Emission = IN.uv_MainTex.x; 이렇게 바꾸어 볼까요? 또는 y값으로 해도 돼요. 제가 아까 말했듯이 uv는 xy 좌표로 사용된다고 했던 것 기억하시죠?

좌에서 우로 0 ~ 1 색이 변하는 것이 보이시나요? y는 그러면, 아래에서 위로 색이 변하겠죠? 즉, (0, 0) -> (1, 1)로 색이 변하는 거죠!! 그럼 여기에 색을 입혀볼게요. 아래의 코드는 float3을 사용하여 색을 입히는 것! 전에 알려드렸던 것을 활용한거예요. 즉, float3(r, g, b)예요.

색이 재밌게도 RGB에서 B는 없었으니 제외를 하고, x 값으로 빨간 색이 진해지죠? 그리고 y값으로 초록색이 진해지는 것을 볼 수 있어요. 이렇게 UV의 값이 어떻게 흘러가는지 알 수 있죠.

UV 텍스쳐 제어하기 !!


방금 위에서 했던 것 처럼, 이제는 텍스쳐를 제어할 거예요. UV에 대한 개념을 지금까지 배웠다고 생각하시면 될거예요!! 참고로 저는 쉽게 UV가 이동하는 것을 보여드리기 위해서 Range를 만들어 인스펙터에서 제어할 수 있도록 만들었는데요. 아까 텍스쳐를 적용을 했다면, Surf 함수를 저와 같이 만들어보는 거예요.

struct Input
        {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Range로 UV가 어떻게 움직이는지 확인
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex + 0.25);
            o.Emission = c.rgb;
            o.Alpha = c.a;
		}

주석 아랫 부분을 보면, 텍스쳐가 들어가고 텍스쳐 uv에 0.25를 더해준 것을 보실 수 있어요. 그러면 아까 사용된 원본의 텍스쳐에서 바뀐 것을 볼 수가 있어요. 마치 왼쪽 밑으로 이동한 것 처럼 보이게 될 거예요.

이렇게 텍스쳐의 UV 값을 바꾸어서 제어를 하실 수 있어요. 방금처럼 한 방식은 왼쪽 밑으로 이동한 것 처럼 나왔지만, X만 제어를 한다면 좌측으로 이동하거나 Y만 제어하면 아래로만 이동하는 것 처럼 되는거죠. 방금은 0.25를 더했지만, 여러분이 원하는 값 만큼 더하거나 빼주실 수 있죠. 그러면 0.25를 더했다면 UV는 어떻게 됐을까요?

처음의 좌표에서 0.25씩 더해주기만 하면 돼요. 그러면 빼거나 곱하거나 나누거나 한다면, 연산만 해주면 값이 나오게 되는거죠. 어렵지 않게 텍스쳐의 UV를 제어할 수 있으니 더욱 다양한 시도를 할 수 있어요!! x 혹은 y만 제어를 하고 싶으시다면, 이 코드를 참고하시기 바래요.

Time / SinTime 활용하기!!


Time과 SinTime은 유니티 내장변수예요. 보통 OpenGL이나 HLSL에서도 많이 사용하지요!! 하단 이미지는 유니티 라이브러리에서 가져온 이미지예요!! 링크 걸어드릴테니 필요하신 분들은 체크하시기 바래요.
Link: https://docs.unity3d.com/2021.3/Documentation/Manual/SL-UnityShaderVariables.html

Time


이 Time을 사용한다면, 텍스쳐나 컬러를 더욱 화려하게 바꾸어 줄 수 있어요. 특히 물을 흐르게 하는 효과는 Time을 사용하면 더욱 효과적이에요. 자 그러면, 어떻게 활용하는지 볼까요?

struct Input
        {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // 시간에 따라 UV가 움직이도록 _Time() 내장변수를 사용하였다
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex + _Time.y);

            // x 또는 y 값으로만 흘러가게도 만들 수 있다, 물 흘러가게 할 때에도 사용한다
            // fixed4 c = tex2D (_MainTex, float2(IN.uv_MainTex.x + _Time.y, IN.uv_MainTex.y));
            // fixed4 c = tex2D (_MainTex, float2(IN.uv_MainTex.x, IN.uv_MainTex.y + _Time.y));
            
            o.Emission = c.rgb;
            o.Alpha = c.a;
		}

일단 제가 작성한 코드는 좌측 하단으로 흘러가도록 하였어요. 이 코드를 참조하였는데, 제대로 나오지 않는다면 두 가지를 확인해주세요.

  • 텍스쳐를 클릭해서 보이는 인스펙터에 Wrap Mode라고 있는데, 이 부분이 Repeat으로 잘 돼있는지 확인해주세요.

  • Scene에서 화면에 보이는 것을 제어하는 속성에 Always Refresh를 체크해주세요.

이 부분들만 해결하시면, 웬만해서 해결이 되요. 이래도 잘 안되신다면, 처음부터 다시 시도해보시거나 댓글을 남겨주세요. 위에 있는 코드를 활용하신다면, 저처럼 나와야 정상이예요!! 왼쪽 하단으로 이동하고 있는 것이 보이시나요? GIF 프레임 때문에 어색하게 보이지만, 이렇게 이동을 하고 있어요!!

그러면 위의 코드에서 x로 이동하는 것과 y로 이동하는 것도 시도를 해보시기를 바래요. 쉽고 재밌게 텍스쳐를 움직이게 만드는 것 또한 참 재밌네요. 참고로 인터페이스를 사용하면, Time 값을 변경할 수 있기 때문에 속도를 빠르게 할 수도 있어요. 아래 코드처럼 말이예요.

SinTime


SinTime 또한 Time과 마찬가지로 사용하는 방법이 어렵지 않아요. 이부분은 텍스쳐로 하기 보다는 컬러로 해서 확인하는 것이 더욱 명확하게 확인이 가능하니, Emission으로 보여드릴게요.

struct Input
        {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
            
            // Sin 시간으로 흐르는 UV 색
            o.Emission = float3(IN.uv_MainTex.x, IN.uv_MainTex.y, _SinTime.w);           
            
            o.Alpha = c.a;
		}       

SinTime은 Sin의 시간을 사용하기 때문에 이 처럼 될 수가 있는데요. 혹시 Sine 그래프에 대하여 잘 모르는 분들을 위해서 참고 이미지 올려드릴게요. 이는 위키피디아를 참고하시기 바래요.
Link: https://en.wikipedia.org/wiki/Sine_and_cosine


오늘도 읽어주셔서 감사해요. 모두들 힘내시기 바래요 !!
공부한 책: 유니티 쉐이더 스타트업

profile
#유니티개발자 #게임 #인플루언서 #ENFJ

0개의 댓글