유니티의 아웃라인 셰이더는 구글에 돌아다니는 레퍼런스가 많아 손쉽게 구현이 가능합니다.
하지만, 자세하게 여러가지를 따지다 보면 불편한 사항이나 제약이 많이 뒤따른다는 것을 쉽게 발견할 수 있습니다.
일반적인 공식으로 알려져있는 아래 수식대로 셰이더를 만들어 아래 오브젝트에 연결해 보면..
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 norm = mul ((fixed3x3)UNITY_MATRIX_MVP, v.normal);
fixed2 offset = TransformViewToProjection(norm.xyz);
o.pos.xy += offset * o.pos.z * _Outline;
o.pos.z += 0.01 * _Outline;
o.color = _OutlineColor;
return o;
3D형태의 메쉬를 가진 오브젝트에는 잘 적용되지만 플랜 상태의 오브젝는 제대로 출려되지 않는 문제가 발생합니다. 아래 그림 참조
이 문제를 해결하기 위해서는 버텍스의 노멀 값 뿐 아니라 사이즈자체도 커지도록 한번 더 계산해 주는 수식을 넣어줘야 합니다.
fixed3 norm = mul ((fixed3x3)UNITY_MATRIX_MVP, v.normal); //요 수식에서
fixed3 norm = mul ((fixed3x3)UNITY_MATRIX_MVP, v.vertex + v.normal); //버텍스 값이 더해지도록 수식을 추가해 준다.
이렇게해도 제대로 출력되지 않을땐 아웃라인 패스 부분에 Cull back 을 추가해 줍니다.
그러면 아래 그림처럼 플랜에서도 정상적인 아웃라인을 만들어 지게 됩니다.
하지만 이 셰이더를 사용할 때 주의해야할 점이 있는데 바로 배칭이 안된다는 것입니다.
스태틱 배칭을 키고나면 버텍스 연산이 다르게 되어 아래그림처럼 엉뚱한 형태로 출력되게 됩니다.
위 셰이더를 사용하고자 할 때는 메터리얼을 따로 만들어 관리하는 것이 최적화에 도움이 될겁니다.
아래는 위 오브젝트의 아웃라인을 구현한 셰이더 코드입니다.
{
Properties {
_MainColor ("Main Color", Color) = (.5,.5,.5,1)
_OutlineColor ("Outline Color", Color) = (0,0,0,1)
_Outline ("Outline width", Range (0, 10)) = 1
_MainTex ("Base (RGB)", 2D) = "white" { }
_Rim ("Rim", Float) = 0.0
_scale("Z Position(Only Plane)", FLoat) = 1.0
//Sorting
_ZTest ("ZTest Less = 4 / Always = 6 ", FLoat) = 1
}
CGINCLUDE
#include "UnityCG.cginc"
#pragma target 3.0
struct v2f {
fixed4 pos : SV_POSITION;
fixed4 color : COLOR;
};
uniform fixed _Outline;
uniform fixed4 _OutlineColor;
uniform fixed _Rim;
uniform fixed _scale;
v2f vert(appdata_base v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
v.vertex.xyz += v.normal.xyz * _scale;
fixed3 norm = mul ((fixed3x3)UNITY_MATRIX_IT_MV, v.normal + v.vertex * _Outline);
fixed2 offset = TransformViewToProjection(norm.xyz);
o.pos.xy += (offset * o.pos.z * _Outline) * 0.001;
o.pos.z += 0.01 * _Outline;
o.color = _OutlineColor;
return o;
}
ENDCG
SubShader {
Tags {"Queue"="Geometry+200" "IgnoreProjector"="True" "RenderType"="Opaque"}
Blend One Zero
// ZTest NotEqual
// ZWrite on
Pass
{
ColorMask 0
}
//
Pass
{
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull off
Blend SrcColor OneMinusSrcColor
ZTest Always
// ZWrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 frag( v2f i ) : COLOR
{
fixed4 c = i.color;
return i.color;
}
ENDCG
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
fixed2 uv_MainTex;
fixed3 worldPos;
};
sampler2D _MainTex;
//sampler2D _BumpMap;
uniform fixed3 _MainColor;
void surf(Input IN, inout SurfaceOutput o) {
// IN.worldPOS.z;
o.Emission = tex2D(_MainTex, IN.uv_MainTex).rgb * _MainColor * _Rim;
// o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG
}
}
'SHADER' 카테고리의 다른 글
유니티와 노트4의 전쟁... 특정 셰이더 코드와 충돌일으킴(vert_img) (0) | 2016.10.29 |
---|---|
유니티 소팅과 셰이더의 연계성..(Unity Sorting Strange..) (0) | 2016.08.24 |
알파 텍스쳐 메모리 절약을 위한 방법 - 알파 텍스쳐 ETC1 2장으로 처리하기 (1) | 2016.07.25 |
유니티 셰이더 - 서피스 셰이더에서 빛 연산을 안하기 위해서는 Albedo가 아닌 Emission을 사용하자. (0) | 2016.07.15 |
유니티 셰이더 - Surface 셰이더에서 알파가 안빠지는 현상 (0) | 2016.07.14 |