You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
17 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System;
  6. using System.Reflection;
  7. using AmplifyShaderEditor;
  8. public static class MaterialPropertyHandlerEx
  9. {
  10. private static System.Type type = null;
  11. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.MaterialPropertyHandler, UnityEditor" ) : type; } }
  12. public static object GetHandler( Shader shader, string name )
  13. {
  14. return MaterialPropertyHandlerEx.Type.InvokeMember( "GetHandler", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { shader, name } );
  15. }
  16. public static void OnGUI( object obj, ref Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor )
  17. {
  18. Type.InvokeMember( "OnGUI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, obj, new object[] { position, prop, label, editor } );
  19. }
  20. public static float GetPropertyHeight( object obj, MaterialProperty prop, string label, MaterialEditor editor )
  21. {
  22. return (float)Type.InvokeMember( "GetPropertyHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, obj, new object[] { prop, label, editor } );
  23. }
  24. public static object PropertyDrawer( object obj )
  25. {
  26. return Type.InvokeMember( "propertyDrawer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty, null, obj, new object[] {} );
  27. }
  28. }
  29. internal class ASEMaterialInspector : ShaderGUI
  30. {
  31. private const string CopyButtonStr = "Copy Values";
  32. private const string PasteButtonStr = "Paste Values";
  33. private const string PreviewModelPref = "ASEMI_PREVIEWMODEL";
  34. private static MaterialEditor m_instance = null;
  35. private static bool m_refreshOnUndo = false;
  36. private bool m_initialized = false;
  37. private double m_lastRenderedTime;
  38. private PreviewRenderUtility m_previewRenderUtility;
  39. private Mesh m_targetMesh;
  40. private Vector2 m_previewDir = new Vector2( 120f, -20f );
  41. private int m_selectedMesh = 0;
  42. // Reflection Fields
  43. private Type m_modelInspectorType = null;
  44. private MethodInfo m_renderMeshMethod = null;
  45. private Type m_previewGUIType = null;
  46. private MethodInfo m_dragMethod = null;
  47. private FieldInfo m_selectedField = null;
  48. private FieldInfo m_infoField = null;
  49. #if UNITY_2018_2_OR_NEWER
  50. public override void OnClosed( Material material )
  51. {
  52. base.OnClosed( material );
  53. CleanUp();
  54. }
  55. #endif
  56. void CleanUp()
  57. {
  58. if( m_previewRenderUtility != null )
  59. {
  60. m_previewRenderUtility.Cleanup();
  61. m_previewRenderUtility = null;
  62. }
  63. }
  64. void UndoRedoPerformed()
  65. {
  66. m_refreshOnUndo = true;
  67. }
  68. ~ASEMaterialInspector()
  69. {
  70. Undo.undoRedoPerformed -= UndoRedoPerformed;
  71. CleanUp();
  72. }
  73. public override void OnGUI( MaterialEditor materialEditor, MaterialProperty[] properties )
  74. {
  75. IOUtils.Init();
  76. Material mat = materialEditor.target as Material;
  77. if( mat == null )
  78. return;
  79. m_instance = materialEditor;
  80. if( !m_initialized )
  81. {
  82. Init();
  83. m_initialized = true;
  84. Undo.undoRedoPerformed += UndoRedoPerformed;
  85. }
  86. if( Event.current.type == EventType.Repaint &&
  87. mat.HasProperty( IOUtils.DefaultASEDirtyCheckId ) &&
  88. mat.GetInt( IOUtils.DefaultASEDirtyCheckId ) == 1 )
  89. {
  90. mat.SetInt( IOUtils.DefaultASEDirtyCheckId, 0 );
  91. UIUtils.ForceUpdateFromMaterial();
  92. //Event.current.Use();
  93. }
  94. if( materialEditor.isVisible )
  95. {
  96. GUILayout.BeginVertical();
  97. {
  98. GUILayout.Space( 3 );
  99. if( GUILayout.Button( "Open in Shader Editor" ) )
  100. {
  101. AmplifyShaderEditorWindow.LoadMaterialToASE( mat );
  102. }
  103. GUILayout.BeginHorizontal();
  104. {
  105. if( GUILayout.Button( CopyButtonStr ) )
  106. {
  107. System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
  108. Shader shader = mat.shader;
  109. int propertyCount = UnityEditor.ShaderUtil.GetPropertyCount( shader );
  110. string allProperties = string.Empty;
  111. for( int i = 0; i < propertyCount; i++ )
  112. {
  113. UnityEditor.ShaderUtil.ShaderPropertyType type = UnityEditor.ShaderUtil.GetPropertyType( shader, i );
  114. string name = UnityEditor.ShaderUtil.GetPropertyName( shader, i );
  115. string valueStr = string.Empty;
  116. switch( type )
  117. {
  118. case UnityEditor.ShaderUtil.ShaderPropertyType.Color:
  119. {
  120. Color value = mat.GetColor( name );
  121. valueStr = value.r.ToString() + IOUtils.VECTOR_SEPARATOR +
  122. value.g.ToString() + IOUtils.VECTOR_SEPARATOR +
  123. value.b.ToString() + IOUtils.VECTOR_SEPARATOR +
  124. value.a.ToString();
  125. }
  126. break;
  127. case UnityEditor.ShaderUtil.ShaderPropertyType.Vector:
  128. {
  129. Vector4 value = mat.GetVector( name );
  130. valueStr = value.x.ToString() + IOUtils.VECTOR_SEPARATOR +
  131. value.y.ToString() + IOUtils.VECTOR_SEPARATOR +
  132. value.z.ToString() + IOUtils.VECTOR_SEPARATOR +
  133. value.w.ToString();
  134. }
  135. break;
  136. case UnityEditor.ShaderUtil.ShaderPropertyType.Float:
  137. {
  138. float value = mat.GetFloat( name );
  139. valueStr = value.ToString();
  140. }
  141. break;
  142. case UnityEditor.ShaderUtil.ShaderPropertyType.Range:
  143. {
  144. float value = mat.GetFloat( name );
  145. valueStr = value.ToString();
  146. }
  147. break;
  148. case UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv:
  149. {
  150. Texture value = mat.GetTexture( name );
  151. valueStr = AssetDatabase.GetAssetPath( value );
  152. Vector2 offset = mat.GetTextureOffset( name );
  153. Vector2 scale = mat.GetTextureScale( name );
  154. valueStr += IOUtils.VECTOR_SEPARATOR + scale.x.ToString() +
  155. IOUtils.VECTOR_SEPARATOR + scale.y.ToString() +
  156. IOUtils.VECTOR_SEPARATOR + offset.x.ToString() +
  157. IOUtils.VECTOR_SEPARATOR + offset.y.ToString();
  158. }
  159. break;
  160. }
  161. allProperties += name + IOUtils.FIELD_SEPARATOR + type + IOUtils.FIELD_SEPARATOR + valueStr;
  162. if( i < ( propertyCount - 1 ) )
  163. {
  164. allProperties += IOUtils.LINE_TERMINATOR;
  165. }
  166. }
  167. EditorPrefs.SetString( IOUtils.MAT_CLIPBOARD_ID, allProperties );
  168. System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
  169. }
  170. if( GUILayout.Button( PasteButtonStr ) )
  171. {
  172. System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
  173. string propertiesStr = EditorPrefs.GetString( IOUtils.MAT_CLIPBOARD_ID, string.Empty );
  174. if( !string.IsNullOrEmpty( propertiesStr ) )
  175. {
  176. string[] propertyArr = propertiesStr.Split( IOUtils.LINE_TERMINATOR );
  177. bool validData = true;
  178. try
  179. {
  180. for( int i = 0; i < propertyArr.Length; i++ )
  181. {
  182. string[] valuesArr = propertyArr[ i ].Split( IOUtils.FIELD_SEPARATOR );
  183. if( valuesArr.Length != 3 )
  184. {
  185. Debug.LogWarning( "Material clipboard data is corrupted" );
  186. validData = false;
  187. break;
  188. }
  189. else if( mat.HasProperty( valuesArr[ 0 ] ) )
  190. {
  191. UnityEditor.ShaderUtil.ShaderPropertyType type = (UnityEditor.ShaderUtil.ShaderPropertyType)Enum.Parse( typeof( UnityEditor.ShaderUtil.ShaderPropertyType ), valuesArr[ 1 ] );
  192. switch( type )
  193. {
  194. case UnityEditor.ShaderUtil.ShaderPropertyType.Color:
  195. {
  196. string[] colorVals = valuesArr[ 2 ].Split( IOUtils.VECTOR_SEPARATOR );
  197. if( colorVals.Length != 4 )
  198. {
  199. Debug.LogWarning( "Material clipboard data is corrupted" );
  200. validData = false;
  201. break;
  202. }
  203. else
  204. {
  205. mat.SetColor( valuesArr[ 0 ], new Color( Convert.ToSingle( colorVals[ 0 ] ),
  206. Convert.ToSingle( colorVals[ 1 ] ),
  207. Convert.ToSingle( colorVals[ 2 ] ),
  208. Convert.ToSingle( colorVals[ 3 ] ) ) );
  209. }
  210. }
  211. break;
  212. case UnityEditor.ShaderUtil.ShaderPropertyType.Vector:
  213. {
  214. string[] vectorVals = valuesArr[ 2 ].Split( IOUtils.VECTOR_SEPARATOR );
  215. if( vectorVals.Length != 4 )
  216. {
  217. Debug.LogWarning( "Material clipboard data is corrupted" );
  218. validData = false;
  219. break;
  220. }
  221. else
  222. {
  223. mat.SetVector( valuesArr[ 0 ], new Vector4( Convert.ToSingle( vectorVals[ 0 ] ),
  224. Convert.ToSingle( vectorVals[ 1 ] ),
  225. Convert.ToSingle( vectorVals[ 2 ] ),
  226. Convert.ToSingle( vectorVals[ 3 ] ) ) );
  227. }
  228. }
  229. break;
  230. case UnityEditor.ShaderUtil.ShaderPropertyType.Float:
  231. {
  232. mat.SetFloat( valuesArr[ 0 ], Convert.ToSingle( valuesArr[ 2 ] ) );
  233. }
  234. break;
  235. case UnityEditor.ShaderUtil.ShaderPropertyType.Range:
  236. {
  237. mat.SetFloat( valuesArr[ 0 ], Convert.ToSingle( valuesArr[ 2 ] ) );
  238. }
  239. break;
  240. case UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv:
  241. {
  242. string[] texVals = valuesArr[ 2 ].Split( IOUtils.VECTOR_SEPARATOR );
  243. if( texVals.Length != 5 )
  244. {
  245. Debug.LogWarning( "Material clipboard data is corrupted" );
  246. validData = false;
  247. break;
  248. }
  249. else
  250. {
  251. mat.SetTexture( valuesArr[ 0 ], AssetDatabase.LoadAssetAtPath<Texture>( texVals[ 0 ] ) );
  252. mat.SetTextureScale( valuesArr[ 0 ], new Vector2( Convert.ToSingle( texVals[ 1 ] ), Convert.ToSingle( texVals[ 2 ] ) ) );
  253. mat.SetTextureOffset( valuesArr[ 0 ], new Vector2( Convert.ToSingle( texVals[ 3 ] ), Convert.ToSingle( texVals[ 4 ] ) ) );
  254. }
  255. }
  256. break;
  257. }
  258. }
  259. }
  260. }
  261. catch( Exception e )
  262. {
  263. Debug.LogException( e );
  264. validData = false;
  265. }
  266. if( validData )
  267. {
  268. materialEditor.PropertiesChanged();
  269. UIUtils.CopyValuesFromMaterial( mat );
  270. }
  271. else
  272. {
  273. EditorPrefs.SetString( IOUtils.MAT_CLIPBOARD_ID, string.Empty );
  274. }
  275. }
  276. System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
  277. }
  278. }
  279. GUILayout.EndHorizontal();
  280. GUILayout.Space( 5 );
  281. }
  282. GUILayout.EndVertical();
  283. }
  284. EditorGUI.BeginChangeCheck();
  285. //base.OnGUI( materialEditor, properties );
  286. // Draw custom properties instead of calling BASE to use single line texture properties
  287. materialEditor.SetDefaultGUIWidths();
  288. if( m_infoField == null )
  289. {
  290. m_infoField = typeof( MaterialEditor ).GetField( "m_InfoMessage", BindingFlags.Instance | BindingFlags.NonPublic );
  291. }
  292. string info = m_infoField.GetValue( materialEditor ) as string;
  293. if( !string.IsNullOrEmpty( info ) )
  294. {
  295. EditorGUILayout.HelpBox( info, MessageType.Info );
  296. }
  297. else
  298. {
  299. GUIUtility.GetControlID( "EditorTextField".GetHashCode(), FocusType.Passive, new Rect( 0f, 0f, 0f, 0f ) );
  300. }
  301. for( int i = 0; i < properties.Length; i++ )
  302. {
  303. if( ( properties[ i ].flags & ( MaterialProperty.PropFlags.HideInInspector | MaterialProperty.PropFlags.PerRendererData ) ) == MaterialProperty.PropFlags.None )
  304. {
  305. if( ( properties[ i ].flags & MaterialProperty.PropFlags.NoScaleOffset ) == MaterialProperty.PropFlags.NoScaleOffset )
  306. {
  307. object obj = MaterialPropertyHandlerEx.GetHandler( mat.shader, properties[ i ].name );
  308. if( obj != null )
  309. {
  310. float height = MaterialPropertyHandlerEx.GetPropertyHeight( obj, properties[ i ], properties[ i ].displayName, materialEditor );
  311. //Rect rect = (Rect)materialEditor.GetType().InvokeMember( "GetPropertyRect", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, materialEditor, new object[] { properties[ i ], properties[ i ].displayName, true } );
  312. Rect rect = EditorGUILayout.GetControlRect( true, height, EditorStyles.layerMaskField );
  313. MaterialPropertyHandlerEx.OnGUI( obj, ref rect, properties[ i ], new GUIContent( properties[ i ].displayName ), materialEditor );
  314. if( MaterialPropertyHandlerEx.PropertyDrawer( obj ) != null )
  315. continue;
  316. rect = EditorGUILayout.GetControlRect( true, height, EditorStyles.layerMaskField );
  317. materialEditor.TexturePropertyMiniThumbnail( rect, properties[ i ], properties[ i ].displayName, string.Empty );
  318. }
  319. else
  320. {
  321. materialEditor.TexturePropertySingleLine( new GUIContent( properties[ i ].displayName ), properties[ i ] );
  322. }
  323. }
  324. else
  325. {
  326. float propertyHeight = materialEditor.GetPropertyHeight( properties[ i ], properties[ i ].displayName );
  327. Rect controlRect = EditorGUILayout.GetControlRect( true, propertyHeight, EditorStyles.layerMaskField, new GUILayoutOption[ 0 ] );
  328. materialEditor.ShaderProperty( controlRect, properties[ i ], properties[ i ].displayName );
  329. }
  330. }
  331. }
  332. EditorGUILayout.Space();
  333. materialEditor.RenderQueueField();
  334. #if UNITY_5_6_OR_NEWER
  335. materialEditor.EnableInstancingField();
  336. #endif
  337. #if UNITY_5_6_2 || UNITY_5_6_3 || UNITY_5_6_4 || UNITY_2017_1_OR_NEWER
  338. materialEditor.DoubleSidedGIField();
  339. #endif
  340. materialEditor.LightmapEmissionProperty();
  341. if( m_refreshOnUndo || EditorGUI.EndChangeCheck() )
  342. {
  343. m_refreshOnUndo = false;
  344. string isEmissive = mat.GetTag( "IsEmissive", false, "false" );
  345. if( isEmissive.Equals( "true" ) )
  346. {
  347. mat.globalIlluminationFlags &= (MaterialGlobalIlluminationFlags)3;
  348. }
  349. else
  350. {
  351. mat.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
  352. }
  353. UIUtils.CopyValuesFromMaterial( mat );
  354. }
  355. if( materialEditor.RequiresConstantRepaint() && m_lastRenderedTime + 0.032999999821186066 < EditorApplication.timeSinceStartup )
  356. {
  357. this.m_lastRenderedTime = EditorApplication.timeSinceStartup;
  358. materialEditor.Repaint();
  359. }
  360. }
  361. private void Init()
  362. {
  363. string guid = EditorPrefs.GetString( PreviewModelPref, "" );
  364. if( !string.IsNullOrEmpty( guid ) )
  365. {
  366. m_targetMesh = AssetDatabase.LoadAssetAtPath<Mesh>( AssetDatabase.GUIDToAssetPath( guid ) );
  367. }
  368. }
  369. public override void OnMaterialPreviewSettingsGUI( MaterialEditor materialEditor )
  370. {
  371. base.OnMaterialPreviewSettingsGUI( materialEditor );
  372. if( UnityEditor.ShaderUtil.hardwareSupportsRectRenderTexture )
  373. {
  374. EditorGUI.BeginChangeCheck();
  375. m_targetMesh = (Mesh)EditorGUILayout.ObjectField( m_targetMesh, typeof( Mesh ), false, GUILayout.MaxWidth( 120 ) );
  376. if( EditorGUI.EndChangeCheck() )
  377. {
  378. if( m_targetMesh != null )
  379. {
  380. EditorPrefs.SetString( PreviewModelPref, AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_targetMesh ) ) );
  381. }
  382. else
  383. {
  384. EditorPrefs.SetString( PreviewModelPref, "" );
  385. }
  386. }
  387. if( m_selectedField == null )
  388. {
  389. m_selectedField = typeof( MaterialEditor ).GetField( "m_SelectedMesh", BindingFlags.Instance | BindingFlags.NonPublic );
  390. }
  391. m_selectedMesh = (int)m_selectedField.GetValue( materialEditor );
  392. if( m_selectedMesh != 0 )
  393. {
  394. if( m_targetMesh != null )
  395. {
  396. m_targetMesh = null;
  397. EditorPrefs.SetString( PreviewModelPref, "" );
  398. }
  399. }
  400. }
  401. }
  402. public override void OnMaterialInteractivePreviewGUI( MaterialEditor materialEditor, Rect r, GUIStyle background )
  403. {
  404. if( Event.current.type == EventType.DragExited )
  405. {
  406. if( DragAndDrop.objectReferences.Length > 0 )
  407. {
  408. GameObject dropped = DragAndDrop.objectReferences[ 0 ] as GameObject;
  409. if( dropped != null )
  410. {
  411. m_targetMesh = AssetDatabase.LoadAssetAtPath<Mesh>( AssetDatabase.GetAssetPath( dropped ) );
  412. EditorPrefs.SetString( PreviewModelPref, AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_targetMesh ) ) );
  413. }
  414. }
  415. }
  416. if( m_targetMesh == null )
  417. {
  418. base.OnMaterialInteractivePreviewGUI( materialEditor, r, background );
  419. return;
  420. }
  421. Material mat = materialEditor.target as Material;
  422. if( m_previewRenderUtility == null )
  423. {
  424. m_previewRenderUtility = new PreviewRenderUtility();
  425. #if UNITY_2017_1_OR_NEWER
  426. m_previewRenderUtility.cameraFieldOfView = 30f;
  427. #else
  428. m_previewRenderUtility.m_CameraFieldOfView = 30f;
  429. #endif
  430. }
  431. if( m_previewGUIType == null )
  432. {
  433. m_previewGUIType = Type.GetType( "PreviewGUI, UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" );
  434. m_dragMethod = m_previewGUIType.GetMethod( "Drag2D", BindingFlags.Static | BindingFlags.Public );
  435. }
  436. if( m_modelInspectorType == null )
  437. {
  438. m_modelInspectorType = Type.GetType( "UnityEditor.ModelInspector, UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" );
  439. m_renderMeshMethod = m_modelInspectorType.GetMethod( "RenderMeshPreview", BindingFlags.Static | BindingFlags.NonPublic );
  440. }
  441. m_previewDir = (Vector2)m_dragMethod.Invoke( m_previewGUIType, new object[] { m_previewDir, r } );
  442. if( Event.current.type == EventType.Repaint )
  443. {
  444. m_previewRenderUtility.BeginPreview( r, background );
  445. m_renderMeshMethod.Invoke( m_modelInspectorType, new object[] { m_targetMesh, m_previewRenderUtility, mat, null, m_previewDir, -1 } );
  446. m_previewRenderUtility.EndAndDrawPreview( r );
  447. }
  448. }
  449. public static MaterialEditor Instance { get { return m_instance; } set { m_instance = value; } }
  450. }