쉐이더그래프에서

평소대로 노드를 짜는데

어쩌다 에러메세지가 뜨는 것을 발견했다.




pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you ex



엥? 이게 뭐여

씬에서는 아무 문제없이 잘 돌아가고 있었다.

네이버에 검색해보니

Pow의 첫번째 인자에 abs를 달아서 사용하라는 말만.


abs 노드가 무슨 역할을 하는지 알아보니 무조건 양수값으로 만들어주는 노드란다.

값이 음수일 경우 -1을 곱해 양수로 만들어주는.


여기저기 물어본 결과

Pow는 음수값을 처리하지 못하니 abs를 달아서 처리해줘라는 에러메세지라는 듯...



근데 일단 씬에선 문제 없이 돌아가기에 그냥 놔두기로 했다(????

포스팅을 쓰는 이유는

나중에 혹여나 문제 생기면 이거 보고 기억하라고......

이번엔 이와 같은 Shader를 만들었기 때문에, 소스를 공개. 해설, 코멘트도 올렸습니다!




원래, 움짤과 같이 파티클이 붕괴하는 것과 같은 연출이 목적이었습니다. 그렇게 때문에, 뚝뚝 아래로 액체가 떨어지는 듯한 베리어 같은 표현으로 했습니다.



참고가 된다면 좋겠군요!




MEMO

-파티클의 감쇠는, 컴포넌트 Aera Effector 2D를 어태치해서 실현하고 있습니다!




소스


Shader "Barrier" { Properties { _Color ("Color", Color) = (1,1,1,1) _DistortionTex ("Disortion Texture(RG)", 2D) = "grey" {} _DistortionPower ("Distortion Power", Range(0, 0.1)) = 0 _width ("Width", Range(0, 0.2)) = 0.05 } SubShader { Tags {"Queue"="Transparent" "RenderType"="Transparent" } GrabPass { "_GrabPassTexture" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" //矩形パルス関数 #define pulse(a, b, x) (step((a),(x)) - step((b),(x))) struct appdata { half4 vertex : POSITION; half4 texcoord : TEXCOORD0; }; struct v2f { half4 vertex : SV_POSITION; half2 uv : TEXCOORD0; half4 grabPos : TEXCOORD1; }; sampler2D _DistortionTex; half4 _DistortionTex_ST; sampler2D _GrabPassTexture; half _DistortionPower; fixed4 _Color; float _width; v2f vert (appdata v) { v2f o = (v2f)0; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _DistortionTex); o.grabPos = ComputeGrabScreenPos(o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { half2 uv = i.grabPos.xy / i.grabPos.w; //歪み用テクスチャをuvスクロール float2 uvTmp = i.uv ; uvTmp.y += _Time.x * 2; //rgは0~1の範囲にあるので、-0.5~0.5にずらす half2 distortion = tex2D(_DistortionTex, uvTmp).rg - 0.5; //歪みの強さ distortion *= _DistortionPower; //円外(uv座標内の半径0.5の外)のピクセルは破棄 float dst = distance(float2(0.5, 0.5), i.uv); if (dst > 0.5) discard; //円の内側の半径 float insideRad = 0.5 - _width; //背面の歪み uv += distortion; fixed4 distortColor = tex2D(_GrabPassTexture, uv)* step(dst,insideRad); //円縁 fixed4 circleOutline = _Color * pulse(insideRad,0.5,dst); return distortColor + circleOutline; } ENDCG } }

}





주요 처리의 흐름


STEP.1

-grapPass로 후면을 취득


STEP.2

-노멀맵으로 후면을 왜곡


STEP.3

-원형틀을 추가하여 완성!




STEP.1 : grapPass로 후면을 취득


일단 grapPass로 후면화면을 취득합니다.

관련 소스는 이하에 쓰여있는 대로입니다.


Tags {"Queue"="Transparent" "RenderType"="Transparent" } GrabPass { "_GrabPassTexture" } Pass { sampler2D _GrabPassTexture;


}


GrabPass {}라고 명기하면, 후면 화면을 얻을 수 있습니다. 다만, 주의할 점도 있는데, Tags{"Queue"="Transparent"}라고 할 필요가 있습니다.


불투명한 모든 오브젝트를 그린 후에 후면을 얻어야하기 때문에, "Queue"="Transparent"로 쓰고 있습니다!



그리고 이하의 소스에서는, 후면 화면의 UV좌표를 얻고 있습니다. 사영 공간에서 텍스쳐 좌표로 변환하는 것입니다. "그러한 것"이라고 이해하면 되겠네요 (웃음)


v2f vert (appdata v) { o.grabPos = ComputeGrabScreenPos(o.vertex); } fixed4 frag (v2f i) : SV_Target { half2 uv = i.grabPos.xy / i.grabPos.w;


}



여기서의 해설은 생략하겠지만, 흥미가 있으신 분은 이쪽의 관련 링크를 체크해주세요!


http://edom18.hateblo.jp/entry/2016/11/28/210605

http://asura.iaigiri.com/OpenGL/gl45.html





STEP2 : 노멀맵으로 후면을 왜곡시키자


다음은 노멀맵의 RG요소로 후면을 왜곡시키겠습니다. 매우 심플합니다! 텍스쳐로 왜곡시키는 이미나 구조는, 제가 기재한 Qiita의 기사를 봐주세요!(https://qiita.com/guru_taka/items/c0292fd25b4e739816b6)



초 간단히 설명하자면, 노멀맵의 울퉁불퉁(RG요소)에 의해, UV좌표가 변화합니다.

그 결과, 후면이 왜곡되듯이 비치는 이미지입니다!


그리고는 UV에 스크롤을 줘서, 노멀맵이 아래를 향해 흐르듯이 했습니다. distortion*=_DistortionPower;는 왜곡의 강함을 나타냅니다. 이런 느낌으로 왜곡 강도가 변화합니다.




이번에 사용한 노말맵은 이쪽입니다.




STEP3 : 원테를 추가해서 완성!


마지막으로, 원테를 추가합니다. 흐름은 이런 느낌!


1. UV좌표계에 반경 0.5이외의 픽셀을 전부 파기

2.원테를 단경 펄스 함수로 작성

3.왜곡 후면과 원테를 더하여 완성!



//1. 円外(uv座標内の半径0.5の外)のピクセルは破棄 float dst = distance(float2(0.5, 0.5), i.uv); if (dst > 0.5) discard; //円の内側の半径 float insideRad = 0.5 - _width; //背面の歪み uv += distortion; fixed4 distortColor = tex2D(_GrabPassTexture, uv)* step(dst,insideRad); //2. 円縁 fixed4 circleOutline = _Color * pulse(insideRad,0.5,dst); //3. 背面+円縁

return distortColor + circleOutline;


단경 펄스 함수는 #define pulse(a, b, x) (step((a), (x)) - step((b), (x))로 정의되고 있습니다.




인용:Shader(HLSL), 手続き的にテクスチャ生成など行うとき使用頻度の高い関数




마지막으로


그리고는, 2D Spirte를 작성하여, 적당한 정방형의 Sprite 이미지를 어태치. 그리고, 상기 shader에 따른 머테리얼을 어태치하면 완성입니다!



Blur UI는 좋아합니까


저는 엄청 좋아합니다.



하겠습니다.




방침


묘사중인 화면의 텍스쳐로서 얻을 수 있는 GrabPass를 사용하여, 그 녀석에 가우시안 블러를 얹는 쉐이더를 작성합니다.




가우시안 블러


이미 여러 사이트에도 쓰여 있는 초 메이져한 알고리즘이기 때문에 자세히는 설명하지 않겠습니다만, 요점은 「묘사 대상의 픽셀에 대하여, 그 주변 픽셀의 색을 거리에 따른 가중치를 두면서 평균을 얻는다」라는 것이 됩니다. 그리고 이 가중치에 가우스 함수를 이용하기 때문에 가우시안 블러라고 불리는 겁니다. 이 함수를 쓰는 것으로 아주 좋은 느낌의 흐림 효과를 얻을 수 있습니다.



묘사 부하


가우시안 블러를 우직하게 구현하면 화면상의 각각의 픽셀에 대하여 그 주변의 필셀을 참조하게 되기 때문에, 흐림의 강도를 높이면, 상당한 속도로 계산 부하가 높아집니다. 예를들어 흐림 범위 20X20이라면 각 픽셀에 대하여 20X20=400회의 샘플링이 걸립니다. 그렇게 때문에, 계산 부하를 줄이는 연구가 필요합니다.


일반적으로는 다음과 같은 방법으로 실행합니다. 먼저 전체에 가로 방향만으로만 흐림을 주고, 그 화면에 세로 방향으로 흐림을 겁니다. 이렇게 하는 것으로, 샘플링 횟수는 20 + 20 = 40회까지 줄일 수 있습니다. 참고로 이렇게 해도 같은 화면 결과를 얻을 수 있습니다.


여기서, 2회의 흐림 처리를 어떻게 실행할 건가가 문제가 됩니다. 이 사이트에서는 화면이 아닌 특정 텍스쳐에 대한 가우시안 블러를 거는 방법이 소개되어 있는데, 스크립트에서 수동으로 쉐이더를 불러들일 수 있는 Graphics.Blit을 써서, 가로 방향과 세로 방향의 2회분의 Graphics.Blit을 부르도록 설계되어 있습니다. 하지만 이번과 같이 GrapPass를 쓰는 경우, 그 방법으로는 잘 돌아가지 않습니다. (스크립트를 부르는 타이밍에선 GrapPass가 작동하지 않기 때문. 아무래도 GrapPass는 카메라에서의 화면으로만 기능하는 것 같습니다. 애초에 카메라의 화면 타이밍 이외에서는 "그 시점에 카메라가 묘사한 화면"이 존재하지 않기 때문에 당연하지만요)


그렇기 때문에, GrapPass를 사용한 이상은 의지로라도 스크립트 없이 구현하지 않으면 안됩니다. 그래서 멀티 패스 쉐이더를 쓰ㅃ니다.


멀티 패스 쉐이더라고 해도 대단한 것은 아닙니다. 요는 하나의 쉐이더에 두 개의 처리(pass)를 넣는 것 뿐입니다. 세로 방향의 흐림과 가로 방향의 흐림을 각각 작성하면 됩니다.





먼저는 GrapPass의 아랫부분을 준비


일단은, GrapPass로 화면을 텍스쳐로 얻고 그대로 표시하는 쉐이더를 작성합니다. 블러 쉐이더는 이것을 원형으로 작성해나갑니다.


 Shader "Custom/Blur"

{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
    SubShader
    {

        Tags{ "Queue" = "Transparent" }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;

            half4 frag(v2f i) : SV_Target
            {
                half4 col = tex2Dproj(_GrabTexture, i.grabPos);
                return col;
            }
            ENDCG
        }
    }
}





가로 방향의 블러를 작성






파라메터


Properties에 가우시안 블러로 주위 픽셀을 취득하는 반경을 파라메터로서 추가합니다.



 Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Blur("Blur", Float) = 10 

    } 




프래그먼트 쉐이더


...(前略)
            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float x = -blur; x <= blur; x += 1)
                {
                    float distance_normalized = abs(x / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(x * _GrabTexture_TexelSize.x, 0, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            } 

(後略)... 




해설


내용이 많기 때문에 해설합니다.


  [loop]
                for (float x = -blur; x <= blur; x += 1) 

                { 



블러 반경에 따라, 현재 위치를 중심으로 왼쪽에서 오른쪽으로 픽셀을 흐리게 하는 루프입니다.




float distance_normalized = abs(x / blur); 



블러 중심에서의 거리를 구합니다. 0~1의 범위로 정규화하고 있기 때문에, 블러 반경이 변화해도 똑같이 처리할 수 있게 됩니다.



 float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0); 

                    weight_total += weight; 


가우시안 블러의 알고리즘에 따라 영향력을 계산합니다.





가우시안 블러의 영향력에 사용하는 함수는 이런 느낌의 형태입니다만, y는 완전한 0은 되지 않으므로, 능숙하게 계수를 조정해서 형태를 맞춰야만 합니다. 대체로 블러 반경의 양끝에 영향력이 0.1 이하가 되도록 조정한 결과, 5.0이 걸려 있습니다.

계산한 영향력은 나중에 평균을 얻을 때 사용하기 때문에, weight_total에 가산해둡니다.



  col += tex2Dproj(_GrabTexture, i.grabPos + float4(x * _GrabTexture_TexelSize.x, 0, 0, 0)) * weight; 


정형한 _GrapTexture_TexelSize.xy에는, GrabPass로 얻은 화면의 텍스쳐 사이즈의 역수가 들어갑니다. 이게 그야말로 1픽셀분의 uv공간상의 거리가 되는 겁니다. 그리고는 이것을 원래의 _GrapPass를 참조하여, 영향력을 더해 가산하면 됩니다.


col /= weight_total; 


그리고 가산한 색을 영향력의 합계로 나누면, 영향력을 고려한 평균값이 구해집니다.





세로 방향 블러를 작성하기


세로 방향 블러를 추가합니다. 가로 방향 블러를 더한 결과의 이미지에, 더해서 세로 방향 블러를 더할 필요가 있기 때문에, GrapPass와 Pass를 하나씩 보충해서 써줍니다. Pass의 내용은 거의 가로 방향 블러와 똑같기 때문에 조금 중복 느낌이 있지만, 이렇게 해야만 하기 때문에 포기하고 작성합니다.


...(前略)
                col /= weight_total;
                return col;
            }
            ENDCG
        }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float y = -blur; y <= blur; y += 1)
                {
                    float distance_normalized = abs(y / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(0, y * _GrabTexture_TexelSize.y, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }

    }
}

 


다 하셨나요?







전문


Shader "Custom/Blur"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Blur("Blur", Float) = 10
    }
    SubShader
    {

        Tags{ "Queue" = "Transparent" }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float x = -blur; x <= blur; x += 1)
                {
                    float distance_normalized = abs(x / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(x * _GrabTexture_TexelSize.x, 0, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }
        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float y = -blur; y <= blur; y += 1)
                {
                    float distance_normalized = abs(y / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(0, y * _GrabTexture_TexelSize.y, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }

    } 

} 



주의점


이번의 흐림 처리는 화면 전체가 아닌 특정 영역에만 대해서 실행하고 있기 때문에, 영역의 경계 부분에서 올바른 결과를 얻지 못할 경우도 있습니다. 실용시 유의하시기 바랍니다.



참고


Unityでガウシアンブラーを実装する - e.blog
http://edom18.hateblo.jp/entry/2018/12/30/171214

ShaderLab: GrabPass
https://docs.unity3d.com/ja/current/Manual/SL-GrabPass.html




원문: https://qiita.com/ruccho_vector/items/651f760b3240a253bd1d

유니티로 3D모델을 평범하게 그리면 폴리곤이 표시됩니다. 여기서는 폴리곤의 정점만을 점으로 표현하는 방법을 소개합니다.


정점의 표현 방법을 바꾸는 것만이라면, 무려 2행의 스크립트만으로 끝납니다. 각각의 정점에 여러 색을 입히는 경우에는 쉐이더를 쓰고 있습니다.







토폴리지를 폴리곤에서 포인트로 변경하기


3D모델의 정점 정보는 Mesh에서 관리되고 있어서, 그 정점을 어떤식으로 그릴지는 MeshTopology로 정의되고 있습니다. 통상은 면을 그리기 위해 트라이앵글 토폴로지가 선택되고 있습니다.



MeshTopology에는 다음과 같은 종류가 있습니다.



 토폴로지 명

형태 

 Triangles

삼각형 

 Quads

 사각형

 Lines

 선

 LineStrip

 선분

 Points

 점




여기서는, 정점을 점으로 표시하기 위해서 MeshTopology.Points를 지정합니다. 와이어프레임으로 표시하고 싶은 경우는 MeshTopology.Lines를 선택합니다.









토폴로지를 변경하고 포인트로 표시하기


토폴로지의 변경은, 스크립트에서 간단하게 실행할 수 있습니다. PointController라는 이름의 스크립트를 작성하고, 다음의 내용을 입력해주세요.


using System.Collections; using System.Collections.Generic; using UnityEngine; public class PointController : MonoBehaviour { void Start () { MeshFilter meshFilter = GetComponent<MeshFilter>(); meshFilter.mesh.SetIndices(meshFilter.mesh.GetIndices(0),MeshTopology.Points,0); }

}


여기서는 GetComponent를 사용해서 MeshFilter컴포넌트를 얻고, 메쉬가 가진 정점 정보의 토포로지를 Points로 바꿔서 다시 저장하고 있습니다.


스크립트를 다 입력하셨다면, 작성한 스크립트를 3D모델에 어태치해서 실행시켜봐주세요. 다음과 같이, 정점이 포인트로 나타난 모델이 표시될 겁니다.






정점의 색을 그라데이션으로 표시하기


점마다(정점마다) 색을 바꾸고 싶은 경우에는, 쉐이더를 쓸 필요가 있습니다. 여기서는 위에서부터 아래로 향하는 그라데이션이 되도록 점마다 색을 입히는 쉐이더를 써보도록 하죠.


쉐이더 파일과 대응하는 머테리얼을 생성합니다. 프로젝트 뷰에서 오른쪽 클릭을 하고, [Create] -> [Shader] -> [Unlit Shader]를 선택해주세요. 이름은 Gradation으로 합니다. 그리고, 그 Gradation 쉐이더를 선택한 상태로 [Create->Material]을 선택해서, 대응하는 Custom_Gradation 머테리얼도 작성합니다.




쉐이더에는 다음의 내용을 입력해주세요.



Shader "Custom/Gradation" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) } SubShader { Tags { "RenderType"="Transparent" } Cull Off ZWrite On Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; float3 worldPos : TEXCOORD0; }; float4 _Color; v2f vert(appdata_base v) { v2f o; float3 n = UnityObjectToWorldNormal(v.normal); o.pos = UnityObjectToClipPos (v.vertex); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } half4 frag (v2f i) : COLOR { float4 red = float4(255.0/255,70.0/255,150.0/255,1); float4 blue = float4(90.0/255,90.0/255,250.0/255,1); return lerp(red, blue, i.worldPos.y*0.2); } ENDCG } } FallBack Off

}



여기서는 버텍스 쉐이더로, 처리하고 있는 정점의 월드 좌표를 계산하고 있습니다. 프래그먼트 쉐이더에서는 이 월드 좌표의 y성분에 따라 정점의 색을 결정합니다. 이쁘게 청색에서 홍색으로 그라데이션이 되도록, Lerp메소드로 보간해서 계산합니다.


실행 결과는 다음과 같습니다.








정점을 움직여서 모래가 흩날리는 이펙트


정점을 법선(노말) 방향으로 움직여서 모래가 흩날리는 듯한 이펙트를 만들 수도 있습니다. 버텍스 쉐이더를 다음과 같이 변경해주세요.


v2f vert(appdata_base v) { v2f o; float3 n = UnityObjectToWorldNormal(v.normal); o.pos = UnityObjectToClipPos (v.vertex) + float4(n * _Displacement, 0); o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o;

}



여기서는, 월드좌표계로 법선 정보를 얻고, 그 방향으로 _Displacement 만큼 정점을 바깥쪽으로 움직이고 있습니다. _Displacement는 프로버티 블록에 선언해서, 인스펙터에서 조절할 수 있도록 해놨습니다.









원 출저: http://nn-hokuson.hatenablog.com/entry/2017/06/06/202953


1