Silhouette.shader 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Used to show the outline of the object
  4. //
  5. //=============================================================================
  6. // UNITY_SHADER_NO_UPGRADE
  7. Shader "Valve/VR/Silhouette"
  8. {
  9. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  10. Properties
  11. {
  12. g_vOutlineColor( "Outline Color", Color ) = ( .5, .5, .5, 1 )
  13. g_flOutlineWidth( "Outline width", Range ( .001, 0.03 ) ) = .005
  14. g_flCornerAdjust( "Corner Adjustment", Range( 0, 2 ) ) = .5
  15. }
  16. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  17. CGINCLUDE
  18. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  19. #pragma target 5.0
  20. #pragma multi_compile_instancing
  21. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  22. #include "UnityCG.cginc"
  23. #if UNITY_VERSION >= 201810
  24. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  25. UNITY_INSTANCING_BUFFER_START( Props )
  26. UNITY_DEFINE_INSTANCED_PROP( float4, g_vOutlineColor )
  27. UNITY_DEFINE_INSTANCED_PROP( float, g_flOutlineWidth )
  28. UNITY_DEFINE_INSTANCED_PROP( float, g_flCornerAdjust )
  29. UNITY_INSTANCING_BUFFER_END( Props )
  30. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  31. struct VS_INPUT
  32. {
  33. float4 vPositionOs : POSITION;
  34. float3 vNormalOs : NORMAL;
  35. UNITY_VERTEX_INPUT_INSTANCE_ID
  36. };
  37. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  38. struct PS_INPUT
  39. {
  40. float4 vPositionOs : TEXCOORD0;
  41. float3 vNormalOs : TEXCOORD1;
  42. float4 vPositionPs : SV_POSITION;
  43. UNITY_VERTEX_INPUT_INSTANCE_ID
  44. UNITY_VERTEX_OUTPUT_STEREO
  45. };
  46. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  47. PS_INPUT MainVs( VS_INPUT i )
  48. {
  49. PS_INPUT o;
  50. UNITY_SETUP_INSTANCE_ID( i );
  51. UNITY_INITIALIZE_OUTPUT( PS_INPUT, o );
  52. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );
  53. o.vPositionOs.xyzw = i.vPositionOs.xyzw;
  54. o.vNormalOs.xyz = i.vNormalOs.xyz;
  55. o.vPositionPs = UnityObjectToClipPos( i.vPositionOs.xyzw );
  56. return o;
  57. }
  58. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  59. PS_INPUT Extrude( PS_INPUT vertex )
  60. {
  61. PS_INPUT extruded = vertex;
  62. // Offset along normal in projection space
  63. float3 vNormalVs = mul( ( float3x3 )UNITY_MATRIX_IT_MV, vertex.vNormalOs.xyz );
  64. float2 vOffsetPs = TransformViewToProjection( vNormalVs.xy );
  65. vOffsetPs.xy = normalize( vOffsetPs.xy );
  66. // Calculate position
  67. extruded.vPositionPs = UnityObjectToClipPos( vertex.vPositionOs.xyzw );
  68. extruded.vPositionPs.xy += vOffsetPs.xy * extruded.vPositionPs.w * UNITY_ACCESS_INSTANCED_PROP( Props, g_flOutlineWidth );
  69. return extruded;
  70. }
  71. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  72. [maxvertexcount(18)]
  73. void ExtrudeGs( triangle PS_INPUT inputTriangle[3], inout TriangleStream<PS_INPUT> outputStream )
  74. {
  75. UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 0 ] )
  76. UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 1 ] )
  77. UNITY_SETUP_INSTANCE_ID ( inputTriangle[ 2 ] )
  78. DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 0 ] )
  79. DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 1 ] )
  80. DEFAULT_UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX ( inputTriangle[ 2 ] )
  81. PS_INPUT inputTriangle0 = inputTriangle[ 0 ];
  82. PS_INPUT inputTriangle1 = inputTriangle[ 1 ];
  83. PS_INPUT inputTriangle2 = inputTriangle[ 2 ];
  84. float3 a = normalize(inputTriangle0.vPositionOs.xyz - inputTriangle1.vPositionOs.xyz);
  85. float3 b = normalize(inputTriangle1.vPositionOs.xyz - inputTriangle2.vPositionOs.xyz);
  86. float3 c = normalize(inputTriangle2.vPositionOs.xyz - inputTriangle0.vPositionOs.xyz);
  87. inputTriangle0.vNormalOs = inputTriangle0.vNormalOs + normalize( a - c) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust );
  88. inputTriangle1.vNormalOs = inputTriangle1.vNormalOs + normalize(-a + b) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust );
  89. inputTriangle2.vNormalOs = inputTriangle2.vNormalOs + normalize(-b + c) * UNITY_ACCESS_INSTANCED_PROP( Props, g_flCornerAdjust );
  90. PS_INPUT extrudedTriangle0;
  91. PS_INPUT extrudedTriangle1;
  92. PS_INPUT extrudedTriangle2;
  93. UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 );
  94. UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 );
  95. UNITY_INITIALIZE_OUTPUT( PS_INPUT, extrudedTriangle0 );
  96. extrudedTriangle0 = Extrude( inputTriangle0 );
  97. extrudedTriangle1 = Extrude( inputTriangle1 );
  98. extrudedTriangle2 = Extrude( inputTriangle2 );
  99. outputStream.Append( inputTriangle0 );
  100. outputStream.Append( extrudedTriangle0 );
  101. outputStream.Append( inputTriangle1 );
  102. outputStream.Append( extrudedTriangle0 );
  103. outputStream.Append( extrudedTriangle1 );
  104. outputStream.Append( inputTriangle1 );
  105. outputStream.Append( inputTriangle1 );
  106. outputStream.Append( extrudedTriangle1 );
  107. outputStream.Append( extrudedTriangle2 );
  108. outputStream.Append( inputTriangle1 );
  109. outputStream.Append( extrudedTriangle2 );
  110. outputStream.Append( inputTriangle2 );
  111. outputStream.Append( inputTriangle2 );
  112. outputStream.Append( extrudedTriangle2 );
  113. outputStream.Append( inputTriangle0 );
  114. outputStream.Append( extrudedTriangle2 );
  115. outputStream.Append( extrudedTriangle0 );
  116. outputStream.Append( inputTriangle0 );
  117. }
  118. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  119. fixed4 MainPs( PS_INPUT i ) : SV_Target
  120. {
  121. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( i );
  122. return UNITY_ACCESS_INSTANCED_PROP( Props, g_vOutlineColor );
  123. }
  124. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  125. fixed4 NullPs( PS_INPUT i ) : SV_Target
  126. {
  127. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( i );
  128. return float4( 1.0, 0.0, 1.0, 1.0 );
  129. }
  130. #else
  131. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  132. float4 g_vOutlineColor;
  133. float g_flOutlineWidth;
  134. float g_flCornerAdjust;
  135. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  136. struct VS_INPUT
  137. {
  138. float4 vPositionOs : POSITION;
  139. float3 vNormalOs : NORMAL;
  140. };
  141. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  142. struct PS_INPUT
  143. {
  144. float4 vPositionOs : TEXCOORD0;
  145. float3 vNormalOs : TEXCOORD1;
  146. float4 vPositionPs : SV_POSITION;
  147. };
  148. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  149. PS_INPUT MainVs( VS_INPUT i )
  150. {
  151. PS_INPUT o;
  152. o.vPositionOs.xyzw = i.vPositionOs.xyzw;
  153. o.vNormalOs.xyz = i.vNormalOs.xyz;
  154. #if UNITY_VERSION >= 540
  155. o.vPositionPs = UnityObjectToClipPos( i.vPositionOs.xyzw );
  156. #else
  157. o.vPositionPs = mul( UNITY_MATRIX_MVP, i.vPositionOs.xyzw );
  158. #endif
  159. return o;
  160. }
  161. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  162. PS_INPUT Extrude( PS_INPUT vertex )
  163. {
  164. PS_INPUT extruded = vertex;
  165. // Offset along normal in projection space
  166. float3 vNormalVs = mul( ( float3x3 )UNITY_MATRIX_IT_MV, vertex.vNormalOs.xyz );
  167. float2 vOffsetPs = TransformViewToProjection( vNormalVs.xy );
  168. vOffsetPs.xy = normalize( vOffsetPs.xy );
  169. // Calculate position
  170. #if UNITY_VERSION >= 540
  171. extruded.vPositionPs = UnityObjectToClipPos( vertex.vPositionOs.xyzw );
  172. #else
  173. extruded.vPositionPs = mul( UNITY_MATRIX_MVP, vertex.vPositionOs.xyzw );
  174. #endif
  175. extruded.vPositionPs.xy += vOffsetPs.xy * extruded.vPositionPs.w * g_flOutlineWidth;
  176. return extruded;
  177. }
  178. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  179. [maxvertexcount(18)]
  180. void ExtrudeGs( triangle PS_INPUT inputTriangle[3], inout TriangleStream<PS_INPUT> outputStream )
  181. {
  182. float3 a = normalize(inputTriangle[0].vPositionOs.xyz - inputTriangle[1].vPositionOs.xyz);
  183. float3 b = normalize(inputTriangle[1].vPositionOs.xyz - inputTriangle[2].vPositionOs.xyz);
  184. float3 c = normalize(inputTriangle[2].vPositionOs.xyz - inputTriangle[0].vPositionOs.xyz);
  185. inputTriangle[0].vNormalOs = inputTriangle[0].vNormalOs + normalize( a - c) * g_flCornerAdjust;
  186. inputTriangle[1].vNormalOs = inputTriangle[1].vNormalOs + normalize(-a + b) * g_flCornerAdjust;
  187. inputTriangle[2].vNormalOs = inputTriangle[2].vNormalOs + normalize(-b + c) * g_flCornerAdjust;
  188. PS_INPUT extrudedTriangle0 = Extrude( inputTriangle[0] );
  189. PS_INPUT extrudedTriangle1 = Extrude( inputTriangle[1] );
  190. PS_INPUT extrudedTriangle2 = Extrude( inputTriangle[2] );
  191. outputStream.Append( inputTriangle[0] );
  192. outputStream.Append( extrudedTriangle0 );
  193. outputStream.Append( inputTriangle[1] );
  194. outputStream.Append( extrudedTriangle0 );
  195. outputStream.Append( extrudedTriangle1 );
  196. outputStream.Append( inputTriangle[1] );
  197. outputStream.Append( inputTriangle[1] );
  198. outputStream.Append( extrudedTriangle1 );
  199. outputStream.Append( extrudedTriangle2 );
  200. outputStream.Append( inputTriangle[1] );
  201. outputStream.Append( extrudedTriangle2 );
  202. outputStream.Append( inputTriangle[2] );
  203. outputStream.Append( inputTriangle[2] );
  204. outputStream.Append( extrudedTriangle2 );
  205. outputStream.Append(inputTriangle[0]);
  206. outputStream.Append( extrudedTriangle2 );
  207. outputStream.Append( extrudedTriangle0 );
  208. outputStream.Append( inputTriangle[0] );
  209. }
  210. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  211. fixed4 MainPs( PS_INPUT i ) : SV_Target
  212. {
  213. return g_vOutlineColor;
  214. }
  215. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  216. fixed4 NullPs( PS_INPUT i ) : SV_Target
  217. {
  218. return float4( 1.0, 0.0, 1.0, 1.0 );
  219. }
  220. #endif
  221. ENDCG
  222. SubShader
  223. {
  224. Tags { "RenderType"="Outline" "Queue" = "Geometry-1" }
  225. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  226. // Render the object with stencil=1 to mask out the part that isn't the silhouette
  227. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  228. Pass
  229. {
  230. Tags { "LightMode" = "Always" }
  231. ColorMask 0
  232. Cull Off
  233. ZWrite Off
  234. Stencil
  235. {
  236. Ref 1
  237. Comp always
  238. Pass replace
  239. }
  240. CGPROGRAM
  241. #pragma vertex MainVs
  242. #pragma fragment NullPs
  243. ENDCG
  244. }
  245. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  246. // Render the outline by extruding along vertex normals and using the stencil mask previously rendered. Only render depth, so that the final pass executes
  247. // once per fragment (otherwise alpha blending will look bad).
  248. //-------------------------------------------------------------------------------------------------------------------------------------------------------------
  249. Pass
  250. {
  251. Tags { "LightMode" = "Always" }
  252. Cull Off
  253. ZWrite On
  254. Stencil
  255. {
  256. Ref 1
  257. Comp notequal
  258. Pass keep
  259. Fail keep
  260. }
  261. CGPROGRAM
  262. #pragma vertex MainVs
  263. #pragma geometry ExtrudeGs
  264. #pragma fragment MainPs
  265. ENDCG
  266. }
  267. }
  268. }