You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			261 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			261 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C#
		
	
| 
											2 years ago
										 | #if UNITY_EDITOR | ||
|  | using System; | ||
|  | using System.Linq; | ||
|  | using UnityEditor; | ||
|  | using UnityEngine; | ||
|  | using Object = UnityEngine.Object; | ||
|  | 
 | ||
|  | namespace AllIn1VfxToolkit | ||
|  | { | ||
|  |     public class AllIn1VfxGradientDrawer : MaterialPropertyDrawer | ||
|  |     { | ||
|  |         private int resolution; | ||
|  |         private Texture2D textureAsset; | ||
|  | 
 | ||
|  |         public AllIn1VfxGradientDrawer() | ||
|  |         { | ||
|  |             resolution = 64; | ||
|  |         } | ||
|  | 
 | ||
|  |         public AllIn1VfxGradientDrawer(float res) | ||
|  |         { | ||
|  |             resolution = (int) res; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static bool IsPropertyTypeSuitable(MaterialProperty prop) | ||
|  |         { | ||
|  |             return prop.type == MaterialProperty.PropType.Texture; | ||
|  |         } | ||
|  | 
 | ||
|  |         public string TextureName(MaterialProperty prop) => $"{prop.name}Tex"; | ||
|  | 
 | ||
|  |         public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor) | ||
|  |         { | ||
|  |             if(!IsPropertyTypeSuitable(prop)) | ||
|  |             { | ||
|  |                 EditorGUI.HelpBox(position, $"[Gradient] used on non-texture property \"{prop.name}\"", | ||
|  |                     MessageType.Error); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             if(!AssetDatabase.Contains(prop.targets.FirstOrDefault())) | ||
|  |             { | ||
|  |                 EditorGUI.HelpBox(position, | ||
|  |                     "Save Material To Folder to use this effect", | ||
|  |                     MessageType.Error); | ||
|  |                 return; | ||
|  |             } | ||
|  | 
 | ||
|  |             string textureName = TextureName(prop); | ||
|  | 
 | ||
|  |             Gradient currentGradient = null; | ||
|  |             if(prop.targets.Length == 1) | ||
|  |             { | ||
|  |                 Material target = (Material) prop.targets[0]; | ||
|  |                 string path = AssetDatabase.GetAssetPath(target); | ||
|  |                 textureAsset = GetTextureAsset(path, textureName); | ||
|  |                 if(textureAsset != null) | ||
|  |                     currentGradient = DecodeGradient(prop, textureAsset.name); | ||
|  |                 if(currentGradient == null) | ||
|  |                     currentGradient = new Gradient() { }; | ||
|  | 
 | ||
|  |                 EditorGUI.showMixedValue = false; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 EditorGUI.showMixedValue = true; | ||
|  |             } | ||
|  | 
 | ||
|  |             using(EditorGUI.ChangeCheckScope changeScope = new EditorGUI.ChangeCheckScope()) | ||
|  |             { | ||
|  |                 currentGradient = EditorGUILayout.GradientField(label, currentGradient, GUILayout.Height(15)); | ||
|  | 
 | ||
|  |                 if(changeScope.changed) | ||
|  |                 { | ||
|  |                     string encodedGradient = EncodeGradient(currentGradient); | ||
|  |                     string fullAssetName = textureName + encodedGradient; | ||
|  |                     foreach(Object target in prop.targets) | ||
|  |                     { | ||
|  |                         if(!AssetDatabase.Contains(target)) continue; | ||
|  | 
 | ||
|  |                         string path = AssetDatabase.GetAssetPath(target); | ||
|  |                         Texture2D textureAsset = GetTexture(path, textureName); | ||
|  |                         Undo.RecordObject(textureAsset, "Change Material Gradient"); | ||
|  |                         textureAsset.name = fullAssetName; | ||
|  |                         BakeGradient(currentGradient, textureAsset); | ||
|  |                         EditorUtility.SetDirty(textureAsset); | ||
|  | 
 | ||
|  |                         Material material = (Material) target; | ||
|  |                         material.SetTexture(prop.name, textureAsset); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             EditorGUI.showMixedValue = false; | ||
|  |         } | ||
|  | 
 | ||
|  |         private Texture2D GetTexture(string path, string name) | ||
|  |         { | ||
|  |             textureAsset = GetTextureAsset(path, name); | ||
|  |             if(textureAsset == null) CreateTexture(path, name); | ||
|  |             if(textureAsset.width != resolution) textureAsset.Resize(resolution, 1); | ||
|  |             return textureAsset; | ||
|  |         } | ||
|  | 
 | ||
|  |         private void CreateTexture(string path, string name = "unnamed texture") | ||
|  |         { | ||
|  |             textureAsset = new Texture2D(resolution, 1, TextureFormat.RGBA32, false); | ||
|  |             textureAsset.wrapMode = TextureWrapMode.Clamp; | ||
|  |             textureAsset.filterMode = FilterMode.Bilinear; | ||
|  |             textureAsset.name = name; | ||
|  |             AssetDatabase.AddObjectToAsset(textureAsset, path); | ||
|  |             AssetDatabase.Refresh(); | ||
|  |         } | ||
|  | 
 | ||
|  |         private string EncodeGradient(Gradient gradient) | ||
|  |         { | ||
|  |             if(gradient == null) return null; | ||
|  |             return JsonUtility.ToJson(new GradientRepresentation(gradient)); | ||
|  |         } | ||
|  | 
 | ||
|  |         private Gradient DecodeGradient(MaterialProperty prop, string name) | ||
|  |         { | ||
|  |             string json = name.Substring(TextureName(prop).Length); | ||
|  |             try | ||
|  |             { | ||
|  |                 return JsonUtility.FromJson<GradientRepresentation>(json).ToGradient(); | ||
|  |             } | ||
|  |             catch(Exception) | ||
|  |             { | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private Texture2D GetTextureAsset(string path, string name) | ||
|  |         { | ||
|  |             return AssetDatabase.LoadAllAssetsAtPath(path).FirstOrDefault(asset => asset.name.StartsWith(name)) as | ||
|  |                 Texture2D; | ||
|  |         } | ||
|  | 
 | ||
|  |         private void BakeGradient(Gradient gradient, Texture2D texture) | ||
|  |         { | ||
|  |             if(gradient == null) return; | ||
|  |             for(int x = 0; x < texture.width; x++) | ||
|  |             { | ||
|  |                 Color color = gradient.Evaluate((float) x / (texture.width - 1)); | ||
|  |                 for(int y = 0; y < texture.height; y++) texture.SetPixel(x, y, color); | ||
|  |             } | ||
|  | 
 | ||
|  |             texture.Apply(); | ||
|  |         } | ||
|  | 
 | ||
|  |         [MenuItem("Assets/AllIn1Vfx/Remove All Gradient Textures")] | ||
|  |         static void RemoveAllSubAssets() | ||
|  |         { | ||
|  |             foreach(Object asset in Selection.GetFiltered<Object>(SelectionMode.Assets)) | ||
|  |             { | ||
|  |                 string path = AssetDatabase.GetAssetPath(asset); | ||
|  |                 AssetDatabase.ImportAsset(path); | ||
|  |                 foreach(Object subAsset in AssetDatabase.LoadAllAssetRepresentationsAtPath(path)) | ||
|  |                 { | ||
|  |                     Object.DestroyImmediate(subAsset, true); | ||
|  |                 } | ||
|  |                 AssetDatabase.ImportAsset(path); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         class GradientRepresentation | ||
|  |         { | ||
|  |             public GradientMode mode; | ||
|  |             public ColorKey[] colorKeys; | ||
|  |             public AlphaKey[] alphaKeys; | ||
|  | 
 | ||
|  |             public GradientRepresentation() | ||
|  |             { | ||
|  |             } | ||
|  | 
 | ||
|  |             public GradientRepresentation(Gradient source) | ||
|  |             { | ||
|  |                 FromGradient(source); | ||
|  |             } | ||
|  | 
 | ||
|  |             public void FromGradient(Gradient source) | ||
|  |             { | ||
|  |                 mode = source.mode; | ||
|  |                 colorKeys = source.colorKeys.Select(key => new ColorKey(key)).ToArray(); | ||
|  |                 alphaKeys = source.alphaKeys.Select(key => new AlphaKey(key)).ToArray(); | ||
|  |             } | ||
|  | 
 | ||
|  |             public void ToGradient(Gradient gradient) | ||
|  |             { | ||
|  |                 gradient.mode = mode; | ||
|  |                 gradient.colorKeys = colorKeys.Select(key => key.ToGradientKey()).ToArray(); | ||
|  |                 gradient.alphaKeys = alphaKeys.Select(key => key.ToGradientKey()).ToArray(); | ||
|  |             } | ||
|  | 
 | ||
|  |             public Gradient ToGradient() | ||
|  |             { | ||
|  |                 Gradient gradient = new Gradient(); | ||
|  |                 ToGradient(gradient); | ||
|  |                 return gradient; | ||
|  |             } | ||
|  | 
 | ||
|  |             [Serializable] | ||
|  |             public struct ColorKey | ||
|  |             { | ||
|  |                 public Color color; | ||
|  |                 public float time; | ||
|  | 
 | ||
|  |                 public ColorKey(GradientColorKey source) | ||
|  |                 { | ||
|  |                     color = default; | ||
|  |                     time = default; | ||
|  |                     FromGradientKey(source); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 public void FromGradientKey(GradientColorKey source) | ||
|  |                 { | ||
|  |                     color = source.color; | ||
|  |                     time = source.time; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 public GradientColorKey ToGradientKey() | ||
|  |                 { | ||
|  |                     GradientColorKey key; | ||
|  |                     key.color = color; | ||
|  |                     key.time = time; | ||
|  |                     return key; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             [Serializable] | ||
|  |             public struct AlphaKey | ||
|  |             { | ||
|  |                 public float alpha; | ||
|  |                 public float time; | ||
|  | 
 | ||
|  |                 public AlphaKey(GradientAlphaKey source) | ||
|  |                 { | ||
|  |                     alpha = default; | ||
|  |                     time = default; | ||
|  |                     FromGradientKey(source); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 public void FromGradientKey(GradientAlphaKey source) | ||
|  |                 { | ||
|  |                     alpha = source.alpha; | ||
|  |                     time = source.time; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 public GradientAlphaKey ToGradientKey() | ||
|  |                 { | ||
|  |                     GradientAlphaKey key; | ||
|  |                     key.alpha = alpha; | ||
|  |                     key.time = time; | ||
|  |                     return key; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | #endif |