본문 바로가기
그래픽/TA STUDIO (동아리 활동)

[TA STUDIO] #2. _Time함수와 텍스처 움직이기. (+UV Map으로 속도 변화 주기)

by 케이이이이 2019. 10. 5.

본 포스팅은 청강문화산업대학교의 게임 제작 동아리 L.A.B.S

TA STUDIO에서 공부한 내용을 바탕으로 작성되었습니다.

 


 

#새로운 함수, _Time

저번 시간에 이어서 이제 새로운 함수를 배웁니다.

이름하여 _Time!

 

뭐야... 몰라... 뭔데...

대충 시간에 관련된 함수라는 건 알 것 같네요. 이름이 일단 _Time 이니까요.

잘 모르겠다면, 유니티에게 물어볼까요? 대부분의 상용 엔진은 함수 설명을 위한 문서 페이지를 운영하고 있으니까요.

검색을 해 보면,

출처: https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

뭐야 봐도 모르겠는데?

 

아무튼 중요한 건 마지막 부분입니다.

" 셰이더 내에서 애니메이션을 위해 사용합니다. "

 

자세한 건 3학년 엔진 기초 시간에 다룬다고 하니. 지금은 이정도만 알고 넘어가도록 합시다.

뭐, 백문이 불여일견이라고, 한번 해 볼까요?

 


 

#일단 한번 해보자! 흐르는 물 만들기!

유니티 메인화면, 이젠 익숙하죠?

언제나와 같이 먼저 유니티를 켜줍시다.

흐르는 물을 만들 건데, 음...

일단 간단하게 Quad 오브젝트로 만들어 볼까요?

 

저번에 했던 대로 Quad Object를 생성.

Material과 NewSurfaceShader를 만들고, Material의 Shader에 만든 쉐이더 스크립트를 적용해줍시다.

Quad 오브젝트에 Material를 적용하는 것도 잊지 마세요!

 

그리고 물 텍스쳐를 적용하면 되겠죠?

 

저는 스튜디오장님이 제공해준 텍스쳐를 사용하겠습니다. 스튜디오장님 충성충성^^7!

 

텍스처까지 적용해준 모습.
텍스처 세팅도 잊지 말자.

Alpha Is Tranparency(투명도 적용 여부)불투명한 오브젝트이므로 체크 해제.

Generate Mip Maps(밉맵 생성 여부)도 저번과 같이 체크 해제.

Compression(압축률)None으로 설정해주세요.

 

길게 흐른다는 느낌을 주기 위해 길게 늘렸다.

 

그럼 이제 나머지는 쉐이더 스크립트에서 조작해주면 되겠죠! 쉐이더를 열어봅시다.

 

Shader "Custom/NewSurfaceShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

이젠 익숙해 지셨으려나?

저번과 같이 주석과 필요 없는 부분을 지워줍시다.

이번에도 거칠기나 금속 여부, 추가 빛 연산은 사용하지 않을 거에요!

단, 이번에는 불투명한 오브젝트니 렌더링 타입을 그대로(Opaque) 두시면 되겠습니다.

 

다 하시면 아래와 같이 코드가 깔끔해집니다.

 

Shader "Custom/NewSurfaceShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

 

여기서 먼저, 물이 흐른다는 느낌을 주려면 어떻게 해야 할까요?

간단합니다. 물 텍스처를 이동시키면 되겠죠.

그러한 과정을 하기 위해서는 쉐이더에서 텍스쳐를 어떻게 적용하는지 알아야 합니다.

 

 


 

 

출처: https://ko.wikipedia.org/wiki/UV_%EB%A7%A4%ED%95%91

위 그림처럼

3D Model를 전개도를 펼치듯이 펼쳐서 평면으로 표현하는 것을 UV Map이라고 표현합니다.

(3차원 좌표계에서 각 좌표를 [X·Y·Z]로 표현하듯이, [U·V·W]로 좌표를 부르는 것임.) 

 

우리는 그 UV Map위에 Texture를 입혀서, 다시 3D로 구현하는 것이죠.

 

유니티의 UV 좌표계, 출처: http://www.aclockworkberry.com/uv-coordinate-systems-3ds-max-unity-unreal-engine/

이 텍스쳐의 조작을 위해서, 우리는 UV좌표계를 이용합니다.

웃긴 점은 이게 엔진마다, 프로그램마다 조금씩 다르다는 거죠.

 

언리얼 엔진과 유니티는 반대되는 UV좌표계를 가지고 있습니다만... 일단 넘어가고,

지금은 위쪽 그림만 간단하게 살펴보도록 하죠.

수학에서의 제1사분면과 비슷한 느낌의 좌표계를 사용하고 있네요.

 

텍스쳐를 오른쪽으로 이동시키려면 u좌표를 +, 왼쪽으로는 -

위쪽으로 이동시키려면 v좌표를 +, 아래로는 -를 하면 되겠네요.

 

일단 이정도만 알아둬도 지금은 괜찮을 겁니다!

 


 

다시 돌아옵시다.

지금 우리는 텍스쳐를 움직일 방법이 필요하겠네요.

 

이를 담당하는 코드는 여기에 있습니다.

 

fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

fixed4는 표현할 수 있는 색상의 양을 나타내는데, 지금은 중요하지 않으니 패스하도록 하구요.

그 이후, tex2D와 그 안에 들어가는 내용을 확인해보도록 하겠습니다.

 

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };

 

코드 위쪽을 보시면 _MainTexuv_MainTex를 정의내려주고 있는 것을 확인 할 수 있습니다.

 

구글링을 열심히 해본 결과...

_MainTex: Material Inspector를 통해 접근 가능하도록 처리된 것.
uv_MainTex: 현재 픽셀의 UV 데이터 추출.

...라고 하네요.

 

마지막으로 tex2D는 텍스처와 UV값을 넘기면, 이에 해당하는 RGB색상을 반환한다고 하는데...

 

뭐야 이해시켜줘요 모르겠잖아요.

간단하게 말하면,

tex2D는 _MainTex에서 받아온 텍스쳐

→ IN.uv_MainTex로 받아온 UV 데이터로 접근

→ 그 좌표값의 RGB 값을 가져온다고 보면 되겠습니다.

 

그리고 이후에 그것들을 출력시켜주는 걸 테구요. (다른 연산들이 전부 끝난 후에.)

 

그렇다면, 실험해볼까요?

 

IN.uv_MainTexIN.uv_MainTex.xIN.uv_MainTex.y로 분리할 수 있습니다. 각각 x좌표와 y좌표를 담당하겠죠?

이렇게 분리한 인자를 묶을 때는 float2(인자1, 인자2)로 사용해주시면 됩니다.

 

fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;

fixed4 c = tex2D (_MainTex, float2(IN.uv_MainTex.x, 0.5)) * _Color;

로 바꿔봅시다.

무슨 일이 일어날까요?

 

텍스쳐의 y좌표가 0.5로 고정된 채 주우우욱 그려진다. (같은 x축 내에서의 변화가 없다.)

대충 감이 잡히시나요?

텍스쳐의 x좌표는 제대로 그려졌지만 y좌표는 고정되었기에 이렇게 그려집니다.

 

반대로

fixed4 c = tex2D (_MainTex, float2(0.5, IN.uv_MainTex.y)) * _Color;

를 할 경우에는 이렇게 되죠.

텍스쳐의 x좌표가 0.5로 고정된 채 주우욱 그려진다. (같은 y축 내에서의 변화가 없다.)

어떤 방식인지 대충 이해가 가시나요?

그렇다면,

 

fixed4 c = tex2D(_MainTex, float2(1, 1)) * _Color;

는 어떨까요?

단색 사각형!

예상하신 대로, 단색 사각형이 됩니다.

 

그럼 우리는 이 속성값을 사용하여 물을 흐르게 해야 합니다.

어떻게 해야 할까요?

 

여기서 _Time 함수를 사용합니다.

정확한 반환값은 몰라도, 시간에 따라 값이 변화한다는 것 정도는 유추 할 수 있었습니다.

(그리고 각 값마다 증가량이 다르다는 것도요.)

 

여기서 저는 물을 세로(y축) 방향으로 흐르게 하고 싶으니, uv좌표계에서 x값을 그대로 두고, y값을 시간에 따라 변화시키면 되겠네요! 코드로 작성해 봅시다.

 

fixed4 c = tex2D(_MainTex, float2(IN.uv_MainTex.x, IN.uv_MainTex.y + _Time.y)) * _Color;

 

x값은 그대로 두고, y값에 _Time.y를 더했습니다.

어떤 변화가 일어날까요?

 

오! 흐른다!

흐르게 만드는 데 성공했습니다!

가로로 흐르게 하고 싶다면 반대로 x값을 변화시키고, y값을 가만히 두면 되겠네요.

 

속도를 조절하고 싶다면, 증가값을 *연산을 통해 조절하면 될 테구요.

 

 

#응용심화: 부분별 흐르는 속도·모양 조절.

그럼 응용해봅시다.

 

만약 급격하게 떨어지는 폭포나, 흐르는 물 가운데에 돌이 있어서 물의 흐름이 왜곡 된다면 어떨까요?

어떻게 표현하는 것이 좋을까요?

 

정..답...... 교..수님에게....물어본다...... (끄적)

답은 여러가지가 있겠지만,

여기서는 우리가 직접 UV Map을 조정해

오브젝트의 UV Map을 일그러뜨리는 방식을 사용하려고 합니다.

 

자, 3dsMax를 켜줍시다.

 

3dsMax 기본화면

Plane을 꺼내서, 흐르는 폭포(흐르는 속도 조절) 와

강 한가운데에 돌이 박힌 (흐르는 방향 왜곡) 강을 동시에 만들어 보겠습니다.

 

짠. 대애충 이정도로 해 두죠.

떨어지는 폭포와, 가운데에 돌이 박힌 건 구멍을 뚫어서 만드었습니다.

 

 

UV Map 대칭해서 펴기 힘드니 절반을 잘라내서 Symmetry를 적용했구요.

이제 UV맵을 왜곡시키면 되는데....

 

어떤 식으로?

 

(제가 UV Mapping을 잘 못해서 그렇긴 한데 느낌은 이런 식으로 하면 됩니다.)

 

checker Pattern으로 적용해서 텍스쳐가 왜곡되는 정도를 확인하면서,

 

빨라지는 곳은 하나의 타일이 크고 길게,

왜곡은 맨 마지막 사진처럼 왜곡되는 방향대로.

 

조작하시면 됩니다.

 

저는 대충 이런식으로 해서 왜곡했습니다.

 

왜곡이 끝났으면 유니티로 불러와야겠죠.

일단 3dsMax에서 오브젝트를 Export 해 줍시다.

File - Export - Expert...

 

FBX 확장자로 내보내겠습니다.
뭔가 그러면 창이 뜨는데 패스.

...하고 유니티로 돌아옵니다!

 

방금 만든 FBX 파일을 가져와서 화면에 배치합니다.

 

 

네. 요로코롬요.

그리고, 아까전에 흐르게 만든 물의 Material을 적용시켜주면...

 

어..... 좀 과하게 늘어났는데요.
Inspector 창의 Tiling과 Offset을 조정해서 자연스럽게 만들어보자.

타일링과 오프셋 값을 조절하면서 자연스러워지는 값을 적용시켜주세요.

 

저는 대애충... 이정도로 끝!

 

저는 왜곡이 그닥 만족스럽진 않지만... 대충 이런 느낌이 됩니다.

 

주의할 점은 저처럼 Symmetry로 UV Map을 펼치게 되면

텍스쳐를 적용했을때 텍스쳐도 함께 대칭이 된다는 점!

 

물 같은 경우에는 큰 문제가 없지만, 아닐 경우도 있으니 주의하세요!

댓글