[Add] All in one shader
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AllIn1SpriteShader
|
||||
{
|
||||
public class AllIn1ShaderGradientDrawer : MaterialPropertyDrawer
|
||||
{
|
||||
private int resolution;
|
||||
private Texture2D textureAsset;
|
||||
private static MethodInfo reinitializeMethod;
|
||||
private static MethodInfo resizeMethod;
|
||||
|
||||
public AllIn1ShaderGradientDrawer()
|
||||
{
|
||||
resolution = 64;
|
||||
}
|
||||
|
||||
public AllIn1ShaderGradientDrawer(float res)
|
||||
{
|
||||
resolution = (int)res;
|
||||
}
|
||||
|
||||
private static bool IsPropertyTypeSuitable(MaterialProperty prop)
|
||||
{
|
||||
AllIn1ShaderPropertyType propertyType = EditorUtils.GetShaderTypeByMaterialProperty(prop);
|
||||
return propertyType == AllIn1ShaderPropertyType.Texture;
|
||||
}
|
||||
|
||||
private string TextureName(MaterialProperty prop) => $"z{prop.name}Tex";
|
||||
private string OldName(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. Or use the regular Color Ramp instead", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string textureName = TextureName(prop);
|
||||
string oldTextureName = OldName(prop);
|
||||
|
||||
Gradient currentGradient = null;
|
||||
if (prop.targets.Length == 1)
|
||||
{
|
||||
Material target = (Material)prop.targets[0];
|
||||
string path = AssetDatabase.GetAssetPath(target);
|
||||
textureAsset = GetTexture(path, textureName, oldTextureName);
|
||||
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, oldTextureName);
|
||||
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, string possibleOldName)
|
||||
{
|
||||
textureAsset = GetTextureAsset(path, name);
|
||||
if(textureAsset == null)
|
||||
{
|
||||
textureAsset = GetTextureAsset(path, possibleOldName);
|
||||
if(textureAsset != null)
|
||||
{
|
||||
textureAsset.name = textureAsset.name.Replace(possibleOldName, name);
|
||||
EditorUtility.SetDirty(textureAsset);
|
||||
}
|
||||
}
|
||||
if (textureAsset == null) CreateTexture(path, name);
|
||||
if(textureAsset.width != resolution)
|
||||
{
|
||||
ResizeTexture(textureAsset, resolution, 1);
|
||||
EditorUtility.SetDirty(textureAsset);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
return textureAsset;
|
||||
}
|
||||
|
||||
private void ResizeTexture(Texture2D texture, int width, int height)
|
||||
{
|
||||
if(reinitializeMethod == null && resizeMethod == null)
|
||||
{
|
||||
reinitializeMethod = typeof(Texture2D).GetMethod("Reinitialize", new[] { typeof(int), typeof(int) });
|
||||
if(reinitializeMethod == null) resizeMethod = typeof(Texture2D).GetMethod("Resize", new[] { typeof(int), typeof(int) });
|
||||
}
|
||||
|
||||
if(reinitializeMethod != null) reinitializeMethod.Invoke(texture, new object[] { width, height });
|
||||
else if(resizeMethod != null) resizeMethod.Invoke(texture, new object[] { width, height });
|
||||
}
|
||||
|
||||
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/AllIn1Shader Gradients/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);
|
||||
}
|
||||
|
||||
private 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();
|
||||
}
|
||||
|
||||
private 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
|
||||
Reference in New Issue
Block a user