Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
05-16 04:51
관리 메뉴

nomad-programmer

[CG/Unity] Triplanar 본문

CG/Unity

[CG/Unity] Triplanar

scii 2022. 3. 13. 20:04

일반적인 메쉬 오브젝트라면 3D 프로그램에서 UV를 다시 펴서 import 하는 것으로 늘어난 텍스처를 해결할 수 있다. 하지만 예를 들어 게임에서 실시간으로 높은 지형이 튀어 올라오는 기능을 가지고 있다고 생각해보자.
혹은 눈발을 헤치고 지나가면서, 실시간으로 눈이 파이는 효과를 만들어야 한다고 생각해 보자.

그렇다면 미리 옆면에 대응되는 UV를 만들어 놓을 수가 없다. 그러면서도 옆면에는 세로로 주욱 늘어나지 않은, 제대로 된 텍스처가 입혀지도록 만들고 싶다고 생각해보자.

UV가 따로 필요 없으면서 어디라도 텍스쳐가 늘어나지 않고 제대로 입혀지는 기능이 Triplanar이다. 이 기술의 핵심은 World Position을 UV로 사용하는 것이다.

Shader "Custom/Triplanar"
{
    Properties
    {
        [NoScaleOffset]_MainTex ("TopTex", 2D) = "white" {}
        _MainTexUV("tileU,tileV,offsetU,offsetV", vector) = (1,1,0,0)
        [NoScaleOffset]_MainTex2 ("SideTex", 2D) = "white" {}
        _MainTex2UV("tileU,tileV,offsetU,offsetV", vector) = (1,1,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        CGPROGRAM
        #pragma surface surf Standard

        sampler2D _MainTex;
        sampler2D _MainTex2;
        float4 _MainTexUV;
        float4 _MainTex2UV;

        struct Input
        {
            float3 worldPos;
            float3 worldNormal;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            float2 topUV = float2(IN.worldPos.x, IN.worldPos.z);
            float2 frontUV = float2(IN.worldPos.x, IN.worldPos.y);
            float2 sideUV = float2(IN.worldPos.z, IN.worldPos.y);

            float4 topTex = tex2D(_MainTex, topUV * _MainTexUV.xy + _MainTexUV.zw);
            float4 frontTex = tex2D(_MainTex2, frontUV * _MainTex2UV.xy + _MainTex2UV.zw);
            float4 sideTex = tex2D(_MainTex2, sideUV * _MainTex2UV.xy + _MainTex2UV.zw);

            o.Albedo = lerp(topTex, frontTex, abs(IN.worldNormal.z));
            o.Albedo = lerp(o.Albedo, sideTex, abs(IN.worldNormal.x));
            o.Alpha = 1;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

서피스 셰이더 구조에서 normal map을 넣어 블랜딩하려고 시도할 수도 있다. 하지만 서피스 셰이더 구조에서 만들기에는 문제가 생길 수 있다. 
서피스 셰이더는 이렇게 조금 깊이 들어가면 한계를 만나게 되는 구조이다. 간편한 대신 복잡한 컨트롤을 할 때 한계가 느껴진다.

[NoScaleOffset] 을 Properties의 텍스처 앞에 쓰면 UV 컨트롤하는 인터페이스가 없어진다. 그리고 추가로 Vector4로 4자리 숫자를 받아서 각각 UV의 타일링과 옵셋으로 사용하였다. 물론 Float이나 Range 4개로 따로따로 만들어도 되지만, 세로로 너무 길어지는 데다가 변수도 너무 많아져서 이렇게 이용하기도 한다.

Comments