// Amplify Shader Editor - Visual Shader Editing Tool // Copyright (c) Amplify Creations, Lda using System; using UnityEngine; using UnityEditor; using System.Collections.Generic; //using UnityEngine.Rendering.PostProcessing; namespace AmplifyShaderEditor { public enum ASEPostProcessEvent { BeforeTransparent = 0, BeforeStack = 1, AfterStack = 2 } [Serializable] public class ASEPPSHelperBuffer { public string Name; public string Tooltip; } [Serializable] public class ASEPPSHelperTool : EditorWindow { private const string PPSFullTemplate = "// Amplify Shader Editor - Visual Shader Editing Tool\n" + "// Copyright (c) Amplify Creations, Lda \n" + "#if UNITY_POST_PROCESSING_STACK_V2\n" + "using System;\n" + "using UnityEngine;\n" + "using UnityEngine.Rendering.PostProcessing;\n" + "\n" + "[Serializable]\n" + "[PostProcess( typeof( /*PPSRendererClass*/ ), PostProcessEvent./*PPSEventType*/, \"/*PPSMenuEntry*/\", /*AllowInSceneView*/ )]\n" + "public sealed class /*PPSSettingsClass*/ : PostProcessEffectSettings\n" + "{\n" + "/*PPSPropertiesDeclaration*/" + "}\n" + "\n" + "public sealed class /*PPSRendererClass*/ : PostProcessEffectRenderer\n" + "{\n" + "\tpublic override void Render( PostProcessRenderContext context )\n" + "\t{\n" + "\t\tvar sheet = context.propertySheets.Get( Shader.Find( \"/*PPSShader*/\" ) );\n" + "/*PPSPropertySet*/" + "\t\tcontext.command.BlitFullscreenTriangle( context.source, context.destination, sheet, 0 );\n" + "\t}\n" + "}\n" + "#endif\n"; private const string PPSEventType = "/*PPSEventType*/"; private const string PPSRendererClass = "/*PPSRendererClass*/"; private const string PPSSettingsClass = "/*PPSSettingsClass*/"; private const string PPSMenuEntry = "/*PPSMenuEntry*/"; private const string PPSAllowInSceneView = "/*AllowInSceneView*/"; private const string PPSShader = "/*PPSShader*/"; private const string PPSPropertiesDecl = "/*PPSPropertiesDeclaration*/"; private const string PPSPropertySet = "/*PPSPropertySet*/"; public static readonly string PPSPropertySetFormat = "\t\tsheet.properties.{0}( \"{1}\", settings.{1} );\n"; public static readonly string PPSPropertySetNullPointerCheckFormat = "\t\tif(settings.{1}.value != null) sheet.properties.{0}( \"{1}\", settings.{1} );\n"; public static readonly string PPSPropertyDecFormat = "\t[{0}Tooltip( \"{1}\" )]\n" + "\tpublic {2} {3} = new {2} {{ {4} }};\n"; public static readonly Dictionary WireToPPSType = new Dictionary() { { WirePortDataType.FLOAT,"FloatParameter"}, { WirePortDataType.FLOAT2,"Vector4Parameter"}, { WirePortDataType.FLOAT3,"Vector4Parameter"}, { WirePortDataType.FLOAT4,"Vector4Parameter"}, { WirePortDataType.COLOR,"ColorParameter"}, { WirePortDataType.SAMPLER1D,"TextureParameter"}, { WirePortDataType.SAMPLER2D,"TextureParameter"}, { WirePortDataType.SAMPLER3D,"TextureParameter"}, { WirePortDataType.SAMPLERCUBE,"TextureParameter"} }; public static readonly Dictionary WireToPPSValueSet = new Dictionary() { { WirePortDataType.FLOAT,"SetFloat"}, { WirePortDataType.FLOAT2,"SetVector"}, { WirePortDataType.FLOAT3,"SetVector"}, { WirePortDataType.FLOAT4,"SetVector"}, { WirePortDataType.COLOR,"SetColor"}, { WirePortDataType.SAMPLER1D, "SetTexture"}, { WirePortDataType.SAMPLER2D, "SetTexture"}, { WirePortDataType.SAMPLER3D, "SetTexture"}, { WirePortDataType.SAMPLERCUBE,"SetTexture"} }; public static readonly Dictionary ShaderPropertyToPPSType = new Dictionary() { { UnityEditor.ShaderUtil.ShaderPropertyType.Float,"FloatParameter"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Range,"FloatParameter"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Vector,"Vector4Parameter"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Color,"ColorParameter"}, { UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv,"TextureParameter"} }; public static readonly Dictionary ShaderPropertyToPPSSet = new Dictionary() { { UnityEditor.ShaderUtil.ShaderPropertyType.Float,"SetFloat"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Range,"SetFloat"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Vector,"SetVector"}, { UnityEditor.ShaderUtil.ShaderPropertyType.Color,"SetColor"}, { UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv,"SetTexture"} }; private Dictionary m_excludedProperties = new Dictionary { { "_texcoord",true }, { "__dirty",true} }; private Material m_dummyMaterial = null; private DragAndDropTool m_dragAndDropTool; private Rect m_draggableArea; [SerializeField] private string m_rendererClassName = "PPSRenderer"; [SerializeField] private string m_settingsClassName = "PPSSettings"; [SerializeField] private string m_folderPath = "Assets/"; [SerializeField] private string m_menuEntry = string.Empty; [SerializeField] private bool m_allowInSceneView = true; [SerializeField] private ASEPostProcessEvent m_eventType = ASEPostProcessEvent.AfterStack; [SerializeField] private Shader m_currentShader = null; [SerializeField] private List m_tooltips = new List(); [SerializeField] private bool m_tooltipsFoldout = true; private GUIStyle m_contentStyle = null; private GUIStyle m_pathButtonStyle = null; private GUIContent m_pathButtonContent = new GUIContent(); private Vector2 m_scrollPos = Vector2.zero; [MenuItem( "Window/Amplify Shader Editor/Post-Processing Stack Tool", false, 1001 )] static void ShowWindow() { ASEPPSHelperTool window = EditorWindow.GetWindow(); window.titleContent.text = "Post-Processing Stack Tool"; window.minSize = new Vector2( 302, 350 ); window.Show(); } void FetchTooltips() { m_tooltips.Clear(); int propertyCount = UnityEditor.ShaderUtil.GetPropertyCount( m_currentShader ); for( int i = 0; i < propertyCount; i++ ) { //UnityEditor.ShaderUtil.ShaderPropertyType type = UnityEditor.ShaderUtil.GetPropertyType( m_currentShader, i ); string name = UnityEditor.ShaderUtil.GetPropertyName( m_currentShader, i ); string description = UnityEditor.ShaderUtil.GetPropertyDescription( m_currentShader, i ); if( m_excludedProperties.ContainsKey( name )) continue; m_tooltips.Add( new ASEPPSHelperBuffer { Name = name, Tooltip = description } ); } } void OnGUI() { if( m_pathButtonStyle == null ) m_pathButtonStyle = "minibutton"; m_scrollPos = EditorGUILayout.BeginScrollView( m_scrollPos, GUILayout.Height( position.height ) ); EditorGUILayout.BeginVertical( m_contentStyle ); EditorGUI.BeginChangeCheck(); m_currentShader = EditorGUILayout.ObjectField( "Shader", m_currentShader, typeof( Shader ), false ) as Shader; if( EditorGUI.EndChangeCheck() ) { GetInitialInfo( m_currentShader ); } EditorGUILayout.Separator(); EditorGUILayout.LabelField( "Path and Filename" ); EditorGUILayout.BeginHorizontal(); m_pathButtonContent.text = m_folderPath; Vector2 buttonSize = m_pathButtonStyle.CalcSize( m_pathButtonContent ); if( GUILayout.Button( m_pathButtonContent, m_pathButtonStyle, GUILayout.MaxWidth( Mathf.Min( position.width * 0.5f, buttonSize.x ) ) ) ) { string folderpath = EditorUtility.OpenFolderPanel( "Save Texture Array to folder", "Assets/", "" ); folderpath = FileUtil.GetProjectRelativePath( folderpath ); if( string.IsNullOrEmpty( folderpath ) ) m_folderPath = "Assets/"; else m_folderPath = folderpath + "/"; } m_settingsClassName = EditorGUILayout.TextField( m_settingsClassName, GUILayout.ExpandWidth( true ) ); EditorGUILayout.LabelField( ".cs", GUILayout.MaxWidth( 40 ) ); EditorGUILayout.EndHorizontal(); EditorGUILayout.Separator(); m_menuEntry = EditorGUILayout.TextField( "Name", m_menuEntry ); EditorGUILayout.Separator(); m_allowInSceneView = EditorGUILayout.Toggle( "Allow In Scene View", m_allowInSceneView ); EditorGUILayout.Separator(); m_eventType = (ASEPostProcessEvent)EditorGUILayout.EnumPopup( "Event Type", m_eventType ); EditorGUILayout.Separator(); m_tooltipsFoldout = EditorGUILayout.Foldout( m_tooltipsFoldout, "Tooltips" ); if( m_tooltipsFoldout ) { EditorGUI.indentLevel++; for( int i = 0; i < m_tooltips.Count; i++ ) { m_tooltips[ i ].Tooltip = EditorGUILayout.TextField( m_tooltips[ i ].Name, m_tooltips[ i ].Tooltip ); } EditorGUI.indentLevel--; } EditorGUILayout.Separator(); if( GUILayout.Button( "Build" ) ) { System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; string propertiesDecl = string.Empty; string propertiesSet = string.Empty; GetShaderInfoFromShaderAsset( ref propertiesDecl, ref propertiesSet ); string template = PPSFullTemplate; template = template.Replace( PPSRendererClass, m_rendererClassName ); template = template.Replace( PPSSettingsClass, m_settingsClassName ); template = template.Replace( PPSEventType, m_eventType.ToString() ); template = template.Replace( PPSPropertiesDecl, propertiesDecl ); template = template.Replace( PPSPropertySet, propertiesSet ); template = template.Replace( PPSMenuEntry, m_menuEntry ); template = template.Replace( PPSAllowInSceneView, m_allowInSceneView?"true":"false" ); template = template.Replace( PPSShader, m_currentShader.name ); string path = m_folderPath + m_settingsClassName + ".cs"; IOUtils.SaveTextfileToDisk( template, path, false ); System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture; AssetDatabase.Refresh(); } EditorGUILayout.EndVertical(); EditorGUILayout.EndScrollView(); m_draggableArea.size = position.size; m_dragAndDropTool.TestDragAndDrop( m_draggableArea ); } public void GetShaderInfoFromASE( ref string propertiesDecl, ref string propertiesSet ) { List properties = UIUtils.CurrentWindow.OutsideGraph.PropertyNodes.NodesList; int propertyCount = properties.Count; for( int i = 0; i < propertyCount; i++ ) { properties[ i ].GeneratePPSInfo( ref propertiesDecl, ref propertiesSet ); } } public void GetShaderInfoFromShaderAsset( ref string propertiesDecl, ref string propertiesSet ) { bool fetchInitialInfo = false; if( m_currentShader == null ) { Material mat = Selection.activeObject as Material; if( mat != null ) { m_currentShader = mat.shader; } else { m_currentShader = Selection.activeObject as Shader; } fetchInitialInfo = true; } if( m_currentShader != null ) { if( fetchInitialInfo ) GetInitialInfo( m_currentShader ); if( m_dummyMaterial == null ) { m_dummyMaterial = new Material( m_currentShader ); } else { m_dummyMaterial.shader = m_currentShader; } int propertyCount = UnityEditor.ShaderUtil.GetPropertyCount( m_currentShader ); //string allProperties = string.Empty; int validIds = 0; for( int i = 0; i < propertyCount; i++ ) { UnityEditor.ShaderUtil.ShaderPropertyType type = UnityEditor.ShaderUtil.GetPropertyType( m_currentShader, i ); string name = UnityEditor.ShaderUtil.GetPropertyName( m_currentShader, i ); //string description = UnityEditor.ShaderUtil.GetPropertyDescription( m_currentShader, i ); if( m_excludedProperties.ContainsKey( name )) continue; string defaultValue = string.Empty; bool nullPointerCheck = false; switch( type ) { case UnityEditor.ShaderUtil.ShaderPropertyType.Color: { Color value = m_dummyMaterial.GetColor( name ); defaultValue = string.Format( "value = new Color({0}f,{1}f,{2}f,{3}f)", value.r, value.g, value.b, value.a ); } break; case UnityEditor.ShaderUtil.ShaderPropertyType.Vector: { Vector4 value = m_dummyMaterial.GetVector( name ); defaultValue = string.Format( "value = new Vector4({0}f,{1}f,{2}f,{3}f)", value.x, value.y, value.z, value.w ); } break; case UnityEditor.ShaderUtil.ShaderPropertyType.Float: { float value = m_dummyMaterial.GetFloat( name ); defaultValue = "value = " + value + "f"; } break; case UnityEditor.ShaderUtil.ShaderPropertyType.Range: { float value = m_dummyMaterial.GetFloat( name ); defaultValue = "value = " + value + "f"; } break; case UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv: { nullPointerCheck = true; } break; } propertiesDecl += string.Format( PPSPropertyDecFormat, string.Empty, m_tooltips[ validIds ].Tooltip, ShaderPropertyToPPSType[ type ], name, defaultValue ); propertiesSet += string.Format( nullPointerCheck ? PPSPropertySetNullPointerCheckFormat : PPSPropertySetFormat, ShaderPropertyToPPSSet[ type ], name ); validIds++; } } } private void GetInitialInfo() { MasterNode masterNode = UIUtils.CurrentWindow.OutsideGraph.CurrentMasterNode; m_menuEntry = masterNode.ShaderName.Replace( "Hidden/", string.Empty ).Replace( ".shader", string.Empty ); string name = m_menuEntry; m_rendererClassName = name + "PPSRenderer"; m_settingsClassName = name + "PPSSettings"; m_folderPath = "Assets/"; } private void GetInitialInfo( Shader shader ) { if( shader == null ) { m_scrollPos = Vector2.zero; m_menuEntry = string.Empty; m_rendererClassName = "PPSRenderer"; m_settingsClassName = "PPSSettings"; m_folderPath = "Assets/"; m_tooltips.Clear(); return; } m_menuEntry = shader.name.Replace( "Hidden/", string.Empty ).Replace( ".shader", string.Empty ); m_menuEntry = UIUtils.RemoveInvalidCharacters( m_menuEntry ); string name = m_menuEntry.Replace( "/", string.Empty ); m_rendererClassName = name + "PPSRenderer"; m_settingsClassName = name + "PPSSettings"; m_folderPath = AssetDatabase.GetAssetPath( shader ); m_folderPath = m_folderPath.Replace( System.IO.Path.GetFileName( m_folderPath ), string.Empty ); FetchTooltips(); } public void OnValidObjectsDropped( UnityEngine.Object[] droppedObjs ) { for( int objIdx = 0; objIdx < droppedObjs.Length; objIdx++ ) { Material mat = droppedObjs[ objIdx ] as Material; if( mat != null ) { m_currentShader = mat.shader; GetInitialInfo( mat.shader ); return; } else { Shader shader = droppedObjs[ objIdx ] as Shader; if( shader != null ) { m_currentShader = shader; GetInitialInfo( shader ); return; } } } } private void OnEnable() { m_draggableArea = new Rect( 0, 0, 1, 1 ); m_dragAndDropTool = new DragAndDropTool(); m_dragAndDropTool.OnValidDropObjectEvt += OnValidObjectsDropped; if( m_contentStyle == null ) { m_contentStyle = new GUIStyle( GUIStyle.none ); m_contentStyle.margin = new RectOffset( 6, 4, 5, 5 ); } m_pathButtonStyle = null; //GetInitialInfo(); } private void OnDestroy() { if( m_dummyMaterial != null ) { GameObject.DestroyImmediate( m_dummyMaterial ); m_dummyMaterial = null; } m_dragAndDropTool.Destroy(); m_dragAndDropTool = null; m_tooltips.Clear(); m_tooltips = null; m_contentStyle = null; m_pathButtonStyle = null; m_currentShader = null; } } }