//======= Copyright (c) Valve Corporation, All rights reserved. =============== // // Purpose: Used to show the outline of the object // //============================================================================= // UNITY_SHADER_NO_UPGRADE Shader "Highlight/Silhouette" { //------------------------------------------------------------------------------------------------------------------------------------------------------------- Properties { g_vOutlineColor( "Outline Color", Color ) = ( .5, .5, .5, 1 ) g_flOutlineWidth( "Outline width", Range ( .001, 0.03 ) ) = .005 g_flCornerAdjust( "Corner Adjustment", Range( 0, 2 ) ) = .5 _FlickerTime("闪烁时间0为关闭",Range(0,10)) = 3 } //------------------------------------------------------------------------------------------------------------------------------------------------------------- CGINCLUDE //------------------------------------------------------------------------------------------------------------------------------------------------------------- #pragma target 5.0 #pragma multi_compile_instancing //------------------------------------------------------------------------------------------------------------------------------------------------------------- #include "UnityCG.cginc" #if UNITY_VERSION >= 201810 //------------------------------------------------------------------------------------------------------------------------------------------------------------- UNITY_INSTANCING_BUFFER_START( Props ) UNITY_DEFINE_INSTANCED_PROP( float4, g_vOutlineColor ) UNITY_DEFINE_INSTANCED_PROP( float, g_flOutlineWidth ) UNITY_DEFINE_INSTANCED_PROP( float, g_flCornerAdjust ) UNITY_DEFINE_INSTANCED_PROP( float, _FlickerTime ) UNITY_INSTANCING_BUFFER_END( Props ) //------------------------------------------------------------------------------------------------------------------------------------------------------------- struct VS_INPUT { float4 vPositionOs : POSITION; float3 vNormalOs : NORMAL; UNITY_VERTEX_INPUT_INSTANCE_ID }; //------------------------------------------------------------------------------------------------------------------------------------------------------------- struct PS_INPUT { float4 vPositionOs : TEXCOORD0; float3 vNormalOs : TEXCOORD1; float4 vPositionPs : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; //------------------------------------------------------------------------------------------------------------------------------------------------------------- PS_INPUT MainVs( VS_INPUT i ) { PS_INPUT o; UNITY_SETUP_INSTANCE_ID( i ); UNITY_INITIALIZE_OUTPUT( PS_INPUT, o ); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o ); o.vPositionOs.xyzw = i.vPositionOs.xyzw; o.vNormalOs.xyz = i.vNormalOs.xyz; o.vPositionPs = UnityObjectToClipPos( i.vPositionOs.xyzw ); return o; } //------------------------------------------------------------------------------------------------------------------------------------------------------------- PS_INPUT Extrude( PS_INPUT vertex ) { PS_INPUT extruded = vertex; // Offset along normal in projection space float3 vNormalVs = mul( ( float3x3 )UNITY_MATRIX_IT_MV, vertex.vNormalOs.xyz ); float2 vOffsetPs = TransformViewToProjection( vNormalVs.xy ); vOffsetPs.xy = normalize( vOffsetPs.xy ); // Calculate position extruded.vPositionPs = UnityObjectToClipPos( vertex.vPositionOs.xyzw ); extruded.vPositionPs.xy += vOffsetPs.xy * extruded.vPositionPs.w * UNITY_ACCESS_INSTANCED_PROP( Props, g_flOutlineWidth ); return extruded; } //------------------------------------------------------------------------------------------------------------------------------------------------------------- [maxvertexcount(18)] void ExtrudeGs( triangle PS_INPUT inputTriangle[3], inout TriangleStream outputStream ) { UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 0 ] ) UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 1 ] ) UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 2 ] ) DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 0 ] ) DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 1 ] ) DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 2 ] ) PS_INPUT inputTriangle0 = inputTriangle[ 0 ]; PS_INPUT inputTriangle1 = inputTriangle[ 1 ]; PS_INPUT inputTriangle2 = inputTriangle[ 2 ]; float3 a = normalize(inputTriangle0.vPositionOs.xyz - inputTriangle1.vPositionOs.xyz); float3 b = normalize(inputTriangle1.vPositionOs.xyz - inputTriangle2.vPositionOs.xyz); float3 c = normalize(inputTriangle2.vPositionOs.xyz - inputTriangle0.vPositionOs.xyz); inputTriangle0.vNormalOs = inputTriangle0.vNormalOs + normalize( a - c) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust ); inputTriangle1.vNormalOs = inputTriangle1.vNormalOs + normalize(-a + b) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust ); inputTriangle2.vNormalOs = inputTriangle2.vNormalOs + normalize(-b + c) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust ); PS_INPUT extrudedTriangle0; PS_INPUT extrudedTriangle1; PS_INPUT extrudedTriangle2; UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 ); UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 ); UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 ); extrudedTriangle0 = Extrude( inputTriangle0 ); extrudedTriangle1 = Extrude( inputTriangle1 ); extrudedTriangle2 = Extrude( inputTriangle2 ); outputStream.Append( inputTriangle0 ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( inputTriangle1 ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( extrudedTriangle1 ); outputStream.Append( inputTriangle1 ); outputStream.Append( inputTriangle1 ); outputStream.Append( extrudedTriangle1 ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( inputTriangle1 ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( inputTriangle2 ); outputStream.Append( inputTriangle2 ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( inputTriangle0 ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( inputTriangle0 ); } //------------------------------------------------------------------------------------------------------------------------------------------------------------- fixed4 MainPs( PS_INPUT i ) : SV_Target { UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( i ); g_vOutlineColor = g_vOutlineColor* ((cos( _Time.y*_FlickerTime)+3)/4.0); return UNITY_ACCESS_INSTANCED_PROP( Props, g_vOutlineColor ); } //------------------------------------------------------------------------------------------------------------------------------------------------------------- fixed4 NullPs( PS_INPUT i ) : SV_Target { UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( i ); return float4( 1.0, 0.0, 1.0, 1.0 ); } #else //------------------------------------------------------------------------------------------------------------------------------------------------------------- float4 g_vOutlineColor; float g_flOutlineWidth; float g_flCornerAdjust; //------------------------------------------------------------------------------------------------------------------------------------------------------------- struct VS_INPUT { float4 vPositionOs : POSITION; float3 vNormalOs : NORMAL; }; //------------------------------------------------------------------------------------------------------------------------------------------------------------- struct PS_INPUT { float4 vPositionOs : TEXCOORD0; float3 vNormalOs : TEXCOORD1; float4 vPositionPs : SV_POSITION; }; //------------------------------------------------------------------------------------------------------------------------------------------------------------- PS_INPUT MainVs( VS_INPUT i ) { PS_INPUT o; o.vPositionOs.xyzw = i.vPositionOs.xyzw; o.vNormalOs.xyz = i.vNormalOs.xyz; #if UNITY_VERSION >= 540 o.vPositionPs = UnityObjectToClipPos( i.vPositionOs.xyzw ); #else o.vPositionPs = mul( UNITY_MATRIX_MVP, i.vPositionOs.xyzw ); #endif return o; } //------------------------------------------------------------------------------------------------------------------------------------------------------------- PS_INPUT Extrude( PS_INPUT vertex ) { PS_INPUT extruded = vertex; // Offset along normal in projection space float3 vNormalVs = mul( ( float3x3 )UNITY_MATRIX_IT_MV, vertex.vNormalOs.xyz ); float2 vOffsetPs = TransformViewToProjection( vNormalVs.xy ); vOffsetPs.xy = normalize( vOffsetPs.xy ); // Calculate position #if UNITY_VERSION >= 540 extruded.vPositionPs = UnityObjectToClipPos( vertex.vPositionOs.xyzw ); #else extruded.vPositionPs = mul( UNITY_MATRIX_MVP, vertex.vPositionOs.xyzw ); #endif extruded.vPositionPs.xy += vOffsetPs.xy * extruded.vPositionPs.w * g_flOutlineWidth; return extruded; } //------------------------------------------------------------------------------------------------------------------------------------------------------------- [maxvertexcount(18)] void ExtrudeGs( triangle PS_INPUT inputTriangle[3], inout TriangleStream outputStream ) { float3 a = normalize(inputTriangle[0].vPositionOs.xyz - inputTriangle[1].vPositionOs.xyz); float3 b = normalize(inputTriangle[1].vPositionOs.xyz - inputTriangle[2].vPositionOs.xyz); float3 c = normalize(inputTriangle[2].vPositionOs.xyz - inputTriangle[0].vPositionOs.xyz); inputTriangle[0].vNormalOs = inputTriangle[0].vNormalOs + normalize( a - c) * g_flCornerAdjust; inputTriangle[1].vNormalOs = inputTriangle[1].vNormalOs + normalize(-a + b) * g_flCornerAdjust; inputTriangle[2].vNormalOs = inputTriangle[2].vNormalOs + normalize(-b + c) * g_flCornerAdjust; PS_INPUT extrudedTriangle0 = Extrude( inputTriangle[0] ); PS_INPUT extrudedTriangle1 = Extrude( inputTriangle[1] ); PS_INPUT extrudedTriangle2 = Extrude( inputTriangle[2] ); outputStream.Append( inputTriangle[0] ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( inputTriangle[1] ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( extrudedTriangle1 ); outputStream.Append( inputTriangle[1] ); outputStream.Append( inputTriangle[1] ); outputStream.Append( extrudedTriangle1 ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( inputTriangle[1] ); outputStream.Append( extrudedTriangle2 ); outputStream.Append( inputTriangle[2] ); outputStream.Append( inputTriangle[2] ); outputStream.Append( extrudedTriangle2 ); outputStream.Append(inputTriangle[0]); outputStream.Append( extrudedTriangle2 ); outputStream.Append( extrudedTriangle0 ); outputStream.Append( inputTriangle[0] ); } //------------------------------------------------------------------------------------------------------------------------------------------------------------- fixed4 MainPs( PS_INPUT i ) : SV_Target { g_vOutlineColor = g_vOutlineColor* ((cos( _Time.y*_FlickerTime)+3)/4.0); return g_vOutlineColor; } //------------------------------------------------------------------------------------------------------------------------------------------------------------- fixed4 NullPs( PS_INPUT i ) : SV_Target { return float4( 1.0, 0.0, 1.0, 1.0 ); } #endif ENDCG SubShader { Tags { "RenderType"="Outline" "Queue" = "Geometry-1" } //------------------------------------------------------------------------------------------------------------------------------------------------------------- // Render the object with stencil=1 to mask out the part that isn't the silhouette //------------------------------------------------------------------------------------------------------------------------------------------------------------- Pass { Tags { "LightMode" = "Always" } ColorMask 0 Cull Off ZWrite Off Stencil { Ref 1 Comp always Pass replace } CGPROGRAM #pragma vertex MainVs #pragma fragment NullPs ENDCG } //------------------------------------------------------------------------------------------------------------------------------------------------------------- // Render the outline by extruding along vertex normals and using the stencil mask previously rendered. Only render depth, so that the final pass executes // once per fragment (otherwise alpha blending will look bad). //------------------------------------------------------------------------------------------------------------------------------------------------------------- Pass { Tags { "LightMode" = "Always" } Cull Off ZWrite On Stencil { Ref 1 Comp notequal Pass keep Fail keep } CGPROGRAM #pragma vertex MainVs #pragma geometry ExtrudeGs #pragma fragment MainPs fixed4 _OutLine; struct a2v { float4 vertex:POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; }; v2f vert(a2v v) { v2f o; v.normal = mul((float3x3)UNITY_MATRIX_MV,v.normal); v.normal.z = -.5; return o; } fixed4 frag(v2f i) :COLOR { //闪烁的乒乓的速度,如果脚本传值可以把这段删掉 g_vOutlineColor.g = abs(cos(_Time.x*200)); return g_vOutlineColor; } ENDCG } } }