OutlineNode.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using System;
  4. using UnityEngine;
  5. using UnityEditor;
  6. namespace AmplifyShaderEditor
  7. {
  8. [Serializable]
  9. [NodeAttributes( "Outline", "Miscellaneous", "Uses vertices to simulate an outline around the object" )]
  10. public sealed class OutlineNode : ParentNode
  11. {
  12. enum OutlineAlphaModes
  13. {
  14. None = 0,
  15. Masked,
  16. Transparent,
  17. AlphaPremultiplied
  18. };
  19. private const string CullModePortNameStr = "Cull Mode";
  20. private const string AlphaModePortNameStr = "Alpha";
  21. private const string MaskedModePortNamStr = "Opacity Mask";
  22. private const string OutlineAlphaModeStr = "Alpha Mode";
  23. private const string OpacityMaskClipValueStr = "Mask Clip Value";
  24. private const string FragmentErrorMessage = "Outline node should only be connected to vertex ports.";
  25. private const string TemplateErrorMessage = "Outline node is only valid on the Standard Surface type";
  26. [SerializeField]
  27. private bool m_noFog = true;
  28. [SerializeField]
  29. private string[] AvailableOutlineModes = { "Vertex Offset", "Vertex Scale", "Custom" };
  30. [SerializeField]
  31. private int[] AvailableOutlineValues = { 0, 1, 2 };
  32. [SerializeField]
  33. private int m_currentSelectedMode = 0;
  34. [SerializeField]
  35. private OutlineAlphaModes m_currentAlphaMode = OutlineAlphaModes.None;
  36. private UpperLeftWidgetHelper m_upperLeftWidget = new UpperLeftWidgetHelper();
  37. [NonSerialized]
  38. private StandardSurfaceOutputNode m_masterNode = null;
  39. [SerializeField]
  40. private int m_zTestMode = 0;
  41. [SerializeField]
  42. private int m_zWriteMode = 0;
  43. [SerializeField]
  44. private CullMode m_cullMode = CullMode.Front;
  45. [SerializeField]
  46. private ColorMaskHelper m_colorMaskHelper = new ColorMaskHelper();
  47. protected override void CommonInit( int uniqueId )
  48. {
  49. base.CommonInit( uniqueId );
  50. m_colorMaskHelper.HideInlineButton();
  51. AddOutputPort( WirePortDataType.FLOAT3, "Out" );
  52. AddInputPort( WirePortDataType.FLOAT3, false, "Color", -1, MasterNodePortCategory.Fragment, 0 );
  53. AddInputPort( WirePortDataType.FLOAT, false, "Alpha", -1, MasterNodePortCategory.Fragment, 2 );
  54. AddInputPort( WirePortDataType.FLOAT, false, "Width", -1, MasterNodePortCategory.Fragment, 1 );
  55. GetInputPortByUniqueId( 2 ).Visible = false;
  56. m_textLabelWidth = 115;
  57. m_hasLeftDropdown = true;
  58. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, AvailableOutlineModes[ m_currentSelectedMode ] ) );
  59. }
  60. public override void PropagateNodeData( NodeData nodeData, ref MasterNodeDataCollector dataCollector )
  61. {
  62. base.PropagateNodeData( nodeData, ref dataCollector );
  63. if( GetInputPortByUniqueId( 0 ).IsConnected )
  64. dataCollector.UsingCustomOutlineColor = true;
  65. if( GetInputPortByUniqueId( 1 ).IsConnected )
  66. dataCollector.UsingCustomOutlineWidth = true;
  67. if( GetInputPortByUniqueId( 2 ).IsConnected )
  68. dataCollector.UsingCustomOutlineAlpha = true;
  69. if( !dataCollector.IsTemplate )
  70. {
  71. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.ZWriteMode = m_zWriteMode;
  72. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.OffsetMode = m_currentSelectedMode;
  73. }
  74. }
  75. public override void AfterCommonInit()
  76. {
  77. base.AfterCommonInit();
  78. if( PaddingTitleLeft == 0 )
  79. {
  80. PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  81. if( PaddingTitleRight == 0 )
  82. PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  83. }
  84. }
  85. public override void Destroy()
  86. {
  87. base.Destroy();
  88. m_upperLeftWidget = null;
  89. }
  90. public override void Draw( DrawInfo drawInfo )
  91. {
  92. base.Draw( drawInfo );
  93. EditorGUI.BeginChangeCheck();
  94. m_currentSelectedMode = m_upperLeftWidget.DrawWidget( this, m_currentSelectedMode, AvailableOutlineModes );
  95. if( EditorGUI.EndChangeCheck() )
  96. {
  97. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, AvailableOutlineModes[ m_currentSelectedMode ] ) );
  98. UpdatePorts();
  99. }
  100. }
  101. void CheckAlphaPortVisibility()
  102. {
  103. InputPort alphaPort = GetInputPortByUniqueId( 2 );
  104. if( m_currentAlphaMode != OutlineAlphaModes.None )
  105. {
  106. if( !alphaPort.Visible )
  107. alphaPort.Visible = true;
  108. if( m_currentAlphaMode == OutlineAlphaModes.Masked )
  109. {
  110. GetInputPortByUniqueId( 2 ).Name = MaskedModePortNamStr;
  111. }
  112. else
  113. {
  114. GetInputPortByUniqueId( 2 ).Name = AlphaModePortNameStr;
  115. }
  116. m_sizeIsDirty = true;
  117. }
  118. if( m_currentAlphaMode == OutlineAlphaModes.None && alphaPort.Visible )
  119. {
  120. alphaPort.Visible = false;
  121. m_sizeIsDirty = true;
  122. }
  123. }
  124. public override void DrawProperties()
  125. {
  126. base.DrawProperties();
  127. if ( m_showErrorMessage )
  128. {
  129. EditorGUILayout.HelpBox( TemplateErrorMessage, MessageType.Error );
  130. }
  131. NodeUtils.DrawPropertyGroup( ref m_propertiesFoldout, Constants.ParameterLabelStr, () =>
  132. {
  133. EditorGUI.BeginChangeCheck();
  134. m_currentSelectedMode = EditorGUILayoutIntPopup( "Type", m_currentSelectedMode, AvailableOutlineModes, AvailableOutlineValues );
  135. if( EditorGUI.EndChangeCheck() )
  136. {
  137. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, AvailableOutlineModes[ m_currentSelectedMode ] ) );
  138. UpdatePorts();
  139. }
  140. EditorGUI.BeginChangeCheck();
  141. m_currentAlphaMode = (OutlineAlphaModes)EditorGUILayoutEnumPopup( OutlineAlphaModeStr, m_currentAlphaMode );
  142. if( EditorGUI.EndChangeCheck() )
  143. {
  144. CheckAlphaPortVisibility();
  145. }
  146. if( m_currentAlphaMode == OutlineAlphaModes.Masked )
  147. {
  148. if( m_masterNode == null )
  149. {
  150. m_masterNode = UIUtils.CurrentWindow.OutsideGraph.CurrentMasterNode as StandardSurfaceOutputNode;
  151. }
  152. if( m_masterNode != null )
  153. {
  154. m_masterNode.ShowOpacityMaskValueUI();
  155. }
  156. }
  157. m_cullMode = (CullMode)EditorGUILayoutEnumPopup( CullModePortNameStr, m_cullMode );
  158. m_zWriteMode = EditorGUILayoutPopup( ZBufferOpHelper.ZWriteModeStr, m_zWriteMode, ZBufferOpHelper.ZWriteModeValues );
  159. m_zTestMode = EditorGUILayoutPopup( ZBufferOpHelper.ZTestModeStr, m_zTestMode, ZBufferOpHelper.ZTestModeLabels );
  160. m_colorMaskHelper.Draw( this );
  161. m_noFog = EditorGUILayoutToggle( "No Fog", m_noFog );
  162. } );
  163. }
  164. void UpdatePorts()
  165. {
  166. if( m_currentSelectedMode == 2 ) //custom mode
  167. {
  168. GetInputPortByUniqueId( 1 ).ChangeProperties( "Offset", WirePortDataType.FLOAT3, false );
  169. }
  170. else
  171. {
  172. GetInputPortByUniqueId( 1 ).ChangeProperties( "Width", WirePortDataType.FLOAT, false );
  173. }
  174. }
  175. public override void OnNodeLogicUpdate( DrawInfo drawInfo )
  176. {
  177. base.OnNodeLogicUpdate( drawInfo );
  178. m_showErrorMessage = ( m_containerGraph.CurrentShaderFunction == null ) ? !m_containerGraph.IsStandardSurface : false;
  179. }
  180. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  181. {
  182. if( dataCollector.IsTemplate )
  183. {
  184. UIUtils.ShowMessage( UniqueId , TemplateErrorMessage, MessageSeverity.Error );
  185. return m_outputPorts[ 0 ].ErrorValue;
  186. }
  187. if( dataCollector.IsFragmentCategory )
  188. {
  189. UIUtils.ShowMessage( UniqueId, FragmentErrorMessage , MessageSeverity.Error );
  190. return m_outputPorts[ 0 ].ErrorValue;
  191. }
  192. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  193. return m_outputPorts[ 0 ].ErrorValue;
  194. m_outputPorts[ 0 ].SetLocalValue( "0", dataCollector.PortCategory );
  195. StandardSurfaceOutputNode masterNode = UIUtils.CurrentWindow.OutsideGraph.CurrentMasterNode as StandardSurfaceOutputNode;
  196. MasterNodeDataCollector outlineDataCollector = new MasterNodeDataCollector();
  197. outlineDataCollector.IsOutlineDataCollector = true;
  198. outlineDataCollector.DirtyNormal = true;
  199. if( dataCollector.SurfaceCustomShadowCaster && dataCollector.CustomOutline )
  200. outlineDataCollector.CopyTextureChannelSizeFrom( ref dataCollector );
  201. InputPort colorPort = GetInputPortByUniqueId( 0 );
  202. InputPort alphaPort = GetInputPortByUniqueId( 2 );
  203. InputPort vertexPort = GetInputPortByUniqueId( 1 );
  204. //if( vertexPort.IsConnected )
  205. //{
  206. // outlineDataCollector.PortCategory = MasterNodePortCategory.Vertex;
  207. // string outlineWidth = vertexPort.GenerateShaderForOutput( ref outlineDataCollector, vertexPort.DataType, true, true );
  208. // outlineDataCollector.AddToVertexLocalVariables( UniqueId, PrecisionType.Float, vertexPort.DataType, "outlineVar", outlineWidth );
  209. // outlineDataCollector.AddVertexInstruction( outlineDataCollector.SpecialLocalVariables, UniqueId, false );
  210. // outlineDataCollector.ClearSpecialLocalVariables();
  211. // outlineDataCollector.AddVertexInstruction( outlineDataCollector.VertexLocalVariables, UniqueId, false );
  212. // outlineDataCollector.ClearVertexLocalVariables();
  213. // // need to check whether this breaks other outputs or not
  214. // UIUtils.CurrentWindow.OutsideGraph.ResetNodesLocalVariables();
  215. //}
  216. outlineDataCollector.PortCategory = MasterNodePortCategory.Fragment;
  217. string outlineColor = colorPort.GeneratePortInstructions( ref outlineDataCollector );// "\to.Emission = " + colorPort.GeneratePortInstructions( ref outlineDataCollector ) + ";";
  218. string alphaValue = alphaPort.Visible ? alphaPort.GeneratePortInstructions( ref outlineDataCollector ) : string.Empty;
  219. bool addTabs = outlineDataCollector.DirtySpecialLocalVariables || alphaPort.Available;
  220. outlineDataCollector.AddInstructions( "\t" + outlineDataCollector.SpecialLocalVariables.TrimStart( '\t' ) );
  221. outlineDataCollector.ClearSpecialLocalVariables();
  222. outlineDataCollector.AddInstructions( ( addTabs ? "\t\t\t" : "" ) + "o.Emission = " + outlineColor + ";" );
  223. if( alphaPort.Visible )
  224. {
  225. if( m_currentAlphaMode == OutlineAlphaModes.Masked )
  226. {
  227. float maskClipValue = 0.5f;
  228. if( masterNode != null )
  229. maskClipValue = masterNode.OpacityMaskClipValue;
  230. if( masterNode.InlineOpacityMaskClipValue.IsValid )
  231. {
  232. RangedFloatNode fnode = UIUtils.GetNode( masterNode.InlineOpacityMaskClipValue.NodeId ) as RangedFloatNode;
  233. if( fnode != null )
  234. {
  235. outlineDataCollector.AddToProperties( fnode.UniqueId, fnode.GetPropertyValue(), fnode.OrderIndex );
  236. outlineDataCollector.AddToUniforms( fnode.UniqueId, fnode.GetUniformValue() );
  237. }
  238. else
  239. {
  240. IntNode inode = UIUtils.GetNode( masterNode.InlineOpacityMaskClipValue.NodeId ) as IntNode;
  241. outlineDataCollector.AddToProperties( inode.UniqueId, inode.GetPropertyValue(), inode.OrderIndex );
  242. outlineDataCollector.AddToUniforms( inode.UniqueId, inode.GetUniformValue() );
  243. }
  244. }
  245. else
  246. {
  247. outlineDataCollector.AddToProperties( -1, string.Format( IOUtils.MaskClipValueProperty, OpacityMaskClipValueStr, maskClipValue ), -1 );
  248. outlineDataCollector.AddToUniforms( -1, string.Format( IOUtils.MaskClipValueUniform, maskClipValue ) );
  249. }
  250. outlineDataCollector.AddInstructions( ( addTabs ? "\n\t\t\t" : "" ) + "clip( " + alphaValue + " - " + masterNode.InlineOpacityMaskClipValue.GetValueOrProperty( IOUtils.MaskClipValueName, false ) + " );" );
  251. }
  252. else
  253. {
  254. outlineDataCollector.AddInstructions( ( addTabs ? "\n\t\t\t" : "" ) + "o.Alpha = " + alphaValue + ";" );
  255. }
  256. }
  257. if( outlineDataCollector.UsingWorldNormal )
  258. outlineDataCollector.AddInstructions( ( addTabs ? "\n\t\t\t" : "" ) + "o.Normal = float3(0,0,-1);" );
  259. //Moved vertex port code generation from ln.227 to this after fragment ones
  260. //to correctly include vertex instructions generated by them
  261. UIUtils.CurrentWindow.OutsideGraph.ResetNodesLocalVariables();
  262. outlineDataCollector.PortCategory = MasterNodePortCategory.Vertex;
  263. string outlineWidth = vertexPort.GenerateShaderForOutput( ref outlineDataCollector, vertexPort.DataType, true, true );
  264. outlineDataCollector.AddToVertexLocalVariables( UniqueId, PrecisionType.Float, vertexPort.DataType, "outlineVar", outlineWidth );
  265. outlineDataCollector.AddVertexInstruction( outlineDataCollector.SpecialLocalVariables, UniqueId, false );
  266. outlineDataCollector.ClearSpecialLocalVariables();
  267. outlineDataCollector.AddVertexInstruction( outlineDataCollector.VertexLocalVariables, UniqueId, false );
  268. outlineDataCollector.ClearVertexLocalVariables();
  269. outlineDataCollector.AddASEMacros();
  270. // need to check whether this breaks other outputs or not
  271. UIUtils.CurrentWindow.OutsideGraph.ResetNodesLocalVariables();
  272. if( masterNode != null )
  273. {
  274. masterNode.CheckSamplingMacrosFlag();
  275. //masterNode.AdditionalIncludes.AddToDataCollector( ref outlineDataCollector );
  276. //masterNode.AdditionalPragmas.AddToDataCollector( ref outlineDataCollector );
  277. //masterNode.AdditionalDefines.AddToDataCollector( ref outlineDataCollector );
  278. if( !masterNode.CustomShadowCaster )
  279. masterNode.AdditionalDirectives.AddAllToDataCollector( ref outlineDataCollector );
  280. }
  281. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.InputList = outlineDataCollector.InputList;
  282. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Inputs = outlineDataCollector.Inputs;
  283. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.DirtyInput = outlineDataCollector.DirtyInputs;
  284. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Includes = outlineDataCollector.Includes;
  285. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Pragmas = outlineDataCollector.Pragmas;
  286. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Defines = outlineDataCollector.Defines;
  287. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.StandardAdditionalDirectives = outlineDataCollector.StandardAdditionalDirectives;
  288. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Uniforms = outlineDataCollector.Uniforms;
  289. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.InstancedProperties = outlineDataCollector.InstancedProperties;
  290. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.GrabPasses = outlineDataCollector.GrabPass;
  291. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.UniformList = outlineDataCollector.UniformsList;
  292. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.InstancedPropertiesList = outlineDataCollector.InstancedPropertiesList;
  293. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.VertexData = outlineDataCollector.VertexData;
  294. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Instructions = outlineDataCollector.Instructions;
  295. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.Functions = outlineDataCollector.Functions;
  296. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.LocalFunctions = outlineDataCollector.LocalFunctions;
  297. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.OutlineCullMode = m_cullMode;
  298. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.ZTestMode = m_zTestMode;
  299. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.ZWriteMode = m_zWriteMode;
  300. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.OffsetMode = m_currentSelectedMode;
  301. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.CustomNoFog = m_noFog;
  302. UIUtils.CurrentWindow.OutsideGraph.CurrentStandardSurface.OutlineHelper.ColorMask = m_colorMaskHelper.ColorMask;
  303. dataCollector.CustomOutlineSelectedAlpha = (int)m_currentAlphaMode;
  304. for( int i = 0; i < outlineDataCollector.PropertiesList.Count; i++ )
  305. {
  306. dataCollector.AddToProperties( UniqueId, outlineDataCollector.PropertiesList[ i ].PropertyName, outlineDataCollector.PropertiesList[ i ].OrderIndex );
  307. }
  308. dataCollector.UsingInternalData = dataCollector.UsingInternalData || outlineDataCollector.UsingInternalData;
  309. UIUtils.CurrentWindow.OutsideGraph.ResetNodesLocalVariablesIfNot( MasterNodePortCategory.Vertex );
  310. return "0";
  311. }
  312. public override void ReadFromString( ref string[] nodeParams )
  313. {
  314. base.ReadFromString( ref nodeParams );
  315. m_currentSelectedMode = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  316. m_noFog = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  317. if( UIUtils.CurrentShaderVersion() > 14202 )
  318. m_currentAlphaMode = (OutlineAlphaModes)Enum.Parse( typeof( OutlineAlphaModes ), GetCurrentParam( ref nodeParams ) );
  319. if( UIUtils.CurrentShaderVersion() > 14302 )
  320. {
  321. m_zWriteMode = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  322. m_zTestMode = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  323. }
  324. if( UIUtils.CurrentShaderVersion() > 15304 )
  325. {
  326. m_cullMode = (CullMode)Enum.Parse( typeof( CullMode ), GetCurrentParam( ref nodeParams ) );
  327. }
  328. if( UIUtils.CurrentShaderVersion() > 18926 )
  329. {
  330. m_colorMaskHelper.ReadFromString( ref m_currentReadParamIdx , ref nodeParams );
  331. }
  332. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, AvailableOutlineModes[ m_currentSelectedMode ] ) );
  333. UpdatePorts();
  334. CheckAlphaPortVisibility();
  335. }
  336. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  337. {
  338. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  339. IOUtils.AddFieldValueToString( ref nodeInfo, m_currentSelectedMode );
  340. IOUtils.AddFieldValueToString( ref nodeInfo, m_noFog );
  341. IOUtils.AddFieldValueToString( ref nodeInfo, m_currentAlphaMode );
  342. IOUtils.AddFieldValueToString( ref nodeInfo, m_zWriteMode );
  343. IOUtils.AddFieldValueToString( ref nodeInfo, m_zTestMode );
  344. IOUtils.AddFieldValueToString( ref nodeInfo, m_cullMode );
  345. m_colorMaskHelper.WriteToString( ref nodeInfo );
  346. }
  347. }
  348. }