Files
ichni_Official/Packages/XuanXuanRenderUtility/Editor/ShaderGUIResetTool.cs

399 lines
18 KiB
C#
Raw Normal View History

2025-08-27 21:45:18 -04:00
using System.Collections.Generic;
using System;
using PlasticGui;
using UnityEngine;
using UnityEngine.UIElements;
using ShaderPropertyPack = NBShaderEditor.ShaderGUIHelper.ShaderPropertyPack;
using UnityEditor;
namespace NBShaderEditor
{
public class ShaderGUIResetTool
{
private ShaderGUIHelper _helper;
private Shader _shader;
public bool IsInitResetData = false;
private Stack<(string,string)> _scopeContextStack = new Stack<(string,string)>();
public void CheckAllModifyOnValueChange()
{
foreach (var item in ResetItemDict.Values)
{
item.HasModified = item.CheckHasModifyOnValueChange();
}
}
public void Init(ShaderGUIHelper helper)
{
_helper = helper;
_shader = helper.shader;
IsInitResetData = true;
ResetItemDict.Clear();
_scopeContextStack.Clear();
}
public void EndInit()
{
IsInitResetData = false;
}
public void Update()
{
if (_needUpdate)
{
_needUpdate = false;
CheckAllModifyOnValueChange();
}
}
private bool _needUpdate = false;
public void NeedUpdate()
{
_needUpdate = true;
}
public ShaderGUIResetTool(ShaderGUIHelper helper)
{
Init(helper);
}
public Dictionary<(string, string), ResetItem> ResetItemDict = new Dictionary<(string, string), ResetItem>();
public class ResetItem
{
public ResetItem Parent;
public List<ResetItem> ChildResetItems = new List<ResetItem>();
public Action ResetCallBack;
public Action OnValueChangedCallBack;
public Func<bool> CheckHasModifyOnValueChange;
public Func<bool> CheckHasMixedValueOnValueChange;
public (string, string) NameTuple;
public bool HasModified = false;
public bool HasMixedValue =false;
public bool ChildHasModified = false;
public bool ChildHasMixedValue = false;
public void Init((string, string) nameTuple,Action resetCallBack,Action onValueChangedCallBack,Func<bool> checkHasModifyOnValueChange,Func<bool> checkHasMixedValueOnValueChange)
{
NameTuple = nameTuple;
ResetCallBack = resetCallBack;
OnValueChangedCallBack = onValueChangedCallBack;
CheckHasModifyOnValueChange = checkHasModifyOnValueChange;
CheckHasMixedValueOnValueChange = checkHasMixedValueOnValueChange;
}
public void Execute(bool isParentCall = false)
{
ResetCallBack?.Invoke();
OnValueChangedCallBack?.Invoke();
HasModified = CheckHasModifyOnValueChange();
HasMixedValue = CheckHasMixedValueOnValueChange();
CheckOnValueChange(isParentCall);
foreach (var item in ChildResetItems)
{
item.Execute(true);
}
}
public void CheckOnValueChange(bool isParentCall = false)
{
HasModified = CheckHasModifyOnValueChange();
HasMixedValue = CheckHasMixedValueOnValueChange();
foreach (var childItem in ChildResetItems)
{
HasMixedValue |= childItem.HasMixedValue;
HasModified |= childItem.HasModified;
}
if (!isParentCall && Parent != null)
{
Parent.CheckOnValueChange();
}
}
}
public void CheckOnValueChange((string,string) nameTuple)
{
if (ResetItemDict.ContainsKey(nameTuple))
{
ResetItemDict[nameTuple].CheckOnValueChange();
}
else
{
Debug.LogError("不包含ResetItemDict:"+nameTuple);
}
}
public void DrawResetModifyButton(Rect rect,(string, string) nameTuple, Action resetCallBack,
Action onValueChangedCallBack,Func<bool> checkHasModifyOnValueChange,Func<bool> checkHasMixedValueOnValueChange,bool isSharedGlobalParent = false)
{
ConstructResetItem(nameTuple,resetCallBack,onValueChangedCallBack,checkHasModifyOnValueChange,checkHasMixedValueOnValueChange,isSharedGlobalParent);
DrawResetModifyButtonFinal(rect,nameTuple);
}
public void DrawResetModifyButton(Rect rect,(string,string)nameTuple,ShaderPropertyPack pack, Action resetAction,Action onValueChangedCallBack,VectorValeType vectorValeType = VectorValeType.Undefine,bool isSharedGlobalParent = false)
{
// (string, string) nameTuple = (label, pack.property.name);
ConstructResetItem(nameTuple,
resetAction: ()=>{
SetPropertyToDefaultValue(pack,vectorValeType);
resetAction?.Invoke();
},onValueChangedCallBack:onValueChangedCallBack,
checkHasModifyOnValueChange: () => IsPropertyModified(pack,vectorValeType),
checkHasMixedValueOnValueChange: () => pack.property.hasMixedValue,
isSharedGlobalParent: isSharedGlobalParent
);
if (ResetItemDict.ContainsKey(nameTuple))
{
DrawResetModifyButtonFinal(rect,nameTuple);
}
}
public void DrawResetModifyButton(Rect rect, string label)
{
//大部分功能都是触发子类
ConstructResetItem((label, ""), resetAction: () => { },onValueChangedCallBack: () => { }, () => false, () => false);
DrawResetModifyButtonFinal(rect,(label,""));
}
//isSharedGlobalParent==>有些组件是公用的比如极坐标一类。这些是不会设置父Item的。
public void ConstructResetItem((string,string) nameTuple, Action resetAction,
Action onValueChangedCallBack,Func<bool> checkHasModifyOnValueChange,Func<bool> checkHasMixedValueOnValueChange,bool isSharedGlobalParent = false)
{
if(!IsInitResetData) return;
if (!ResetItemDict.ContainsKey(nameTuple))
{
ResetItem item = new ResetItem();
item.Init(nameTuple,resetAction,onValueChangedCallBack,checkHasModifyOnValueChange,checkHasMixedValueOnValueChange);
ResetItemDict.Add(nameTuple,item);
if (_scopeContextStack.Count > 0 && !isSharedGlobalParent)
{
var contextNameTuple = _scopeContextStack.Peek();
ResetItem parentItem = ResetItemDict[contextNameTuple];
parentItem.ChildResetItems.Add(item);
item.Parent = parentItem;
}
item.CheckOnValueChange();//Init
}
else
{
// Debug.LogError("ResetItem已经存在:"+nameTuple.ToString());
}
//就算是已经ContainsKey了也Push和Pop一下。没有作用但让写法更简单。
_scopeContextStack.Push(nameTuple);
}
public void EndResetModifyButtonScope()
{
if(!IsInitResetData) return;
if(_scopeContextStack.Count == 0) return;
_scopeContextStack.Pop();
}
public float ResetButtonSize => EditorGUIUtility.singleLineHeight;
private GUIContent resetIconContent = new GUIContent();
//仅仅只是Drawer
private void DrawResetModifyButtonFinal(Rect position, (string, string) nameTuple)
{
ResetItem item;
// GUILayout.FlexibleSpace();
if (ResetItemDict.ContainsKey(nameTuple))
{
item = ResetItemDict[nameTuple];
}
else
{
return;
}
float btnSize = ResetButtonSize;
string iconText;
bool isDisabled = true;
GUIStyle iconStyle;
if (item.HasModified || item.HasMixedValue)
{
isDisabled = false;
iconText = "R";
iconStyle = GUI.skin.button;
}
else
{
isDisabled = true;
iconText = "";
iconStyle = GUI.skin.label;
}
resetIconContent.text = iconText;
EditorGUI.BeginDisabledGroup(isDisabled);
// if (GUILayout.Button(iconTexture, GUILayout.Width(btnSize), GUILayout.Height(btnSize)))
if (position.width <= 0)
{
position = GUILayoutUtility.GetRect(resetIconContent, GUI.skin.button, GUILayout.Width(btnSize),
GUILayout.Height(btnSize));
}
if(GUI.Button(position,resetIconContent,iconStyle))
{
item.Execute();
}
EditorGUI.EndDisabledGroup();
}
public void SetPropertyToDefaultValue(ShaderPropertyPack pack,VectorValeType vectorValeType = VectorValeType.Undefine)
{
MaterialProperty property = pack.property;
2026-03-14 03:13:10 -04:00
UnityEngine.Rendering.ShaderPropertyType propertyType = property.propertyType;
if (pack.property.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture && vectorValeType != VectorValeType.Undefine)
2025-08-27 21:45:18 -04:00
{
2026-03-14 03:13:10 -04:00
propertyType = UnityEngine.Rendering.ShaderPropertyType.Vector;//Tilling or Offset
2025-08-27 21:45:18 -04:00
}
switch (propertyType)
{
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Color:
2025-08-27 21:45:18 -04:00
Vector4 colorValue = _shader.GetPropertyDefaultVectorValue(pack.index);
property.colorValue = new Color(colorValue.x, colorValue.y, colorValue.z, colorValue.x);
break;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Vector:
2025-08-27 21:45:18 -04:00
Vector4 defaultVecValue;
Vector4 vecValue;
if (vectorValeType == VectorValeType.Tilling || vectorValeType == VectorValeType.Offset)
{
defaultVecValue = new Vector4(1f, 1f, 0f, 0f);
vecValue = property.textureScaleAndOffset;
}
else
{
defaultVecValue = _shader.GetPropertyDefaultVectorValue(pack.index);
vecValue = property.vectorValue;
}
switch (vectorValeType)
{
case VectorValeType.Undefine: Debug.LogError("VectorValeType is undefined"); break;
case VectorValeType.X: vecValue.x = defaultVecValue.x;property.vectorValue = vecValue;break;
case VectorValeType.Y: vecValue.y = defaultVecValue.y;property.vectorValue = vecValue;break;
case VectorValeType.Z: vecValue.z = defaultVecValue.z;property.vectorValue = vecValue;break;
case VectorValeType.W: vecValue.w = defaultVecValue.w;property.vectorValue = vecValue;break;
case VectorValeType.XY:vecValue.x = defaultVecValue.x; vecValue.y = defaultVecValue.y;
property.vectorValue = vecValue;break;
case VectorValeType.Tilling:vecValue.x = defaultVecValue.x; vecValue.y = defaultVecValue.y;
property.textureScaleAndOffset = vecValue;break;
case VectorValeType.ZW:vecValue.z = defaultVecValue.z; vecValue.w = defaultVecValue.w;
property.vectorValue = vecValue;break;
case VectorValeType.Offset:vecValue.z = defaultVecValue.z; vecValue.w = defaultVecValue.w;
property.textureScaleAndOffset = vecValue;break;
case VectorValeType.XYZ:vecValue.x = defaultVecValue.x; vecValue.y = defaultVecValue.y;
vecValue.z = defaultVecValue.z; property.vectorValue = vecValue;break;
case VectorValeType.XYZW: property.vectorValue = defaultVecValue;break;
}
break;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Float or UnityEngine.Rendering.ShaderPropertyType.Range:
2025-08-27 21:45:18 -04:00
float value = _shader.GetPropertyDefaultFloatValue(pack.index);
property.floatValue = value;
break;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Texture:
2025-08-27 21:45:18 -04:00
if (property.textureValue == null)
{
break;
}
else
{
property.textureValue = null;
break;
}
// return property.textureValue.name == shader.GetPropertyTextureDefaultName(pack.index) ? false : true;
default:
// 如果不属于上述类型,输出提示信息
Debug.Log($"{property.displayName} has no default value or unsupported type");
break;
}
}
public bool IsPropertyModified(ShaderPropertyPack pack,VectorValeType vectorValeType = VectorValeType.Undefine)
{
MaterialProperty property = pack.property;
2026-03-14 03:13:10 -04:00
UnityEngine.Rendering.ShaderPropertyType propertyType = property.propertyType;
if (pack.property.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture && vectorValeType != VectorValeType.Undefine)
2025-08-27 21:45:18 -04:00
{
2026-03-14 03:13:10 -04:00
propertyType = UnityEngine.Rendering.ShaderPropertyType.Vector;//Tilling or Offset
2025-08-27 21:45:18 -04:00
}
switch (propertyType)
{
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Color:
2025-08-27 21:45:18 -04:00
Vector4 colorValue = _shader.GetPropertyDefaultVectorValue(pack.index);
Color color = new Color(colorValue.x, colorValue.y, colorValue.z, colorValue.w);
return property.colorValue == color ? false : true;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Vector:
2025-08-27 21:45:18 -04:00
Vector4 defaultVecValue;
Vector4 vecValue;
if (vectorValeType == VectorValeType.Tilling || vectorValeType == VectorValeType.Offset)
{
defaultVecValue = new Vector4(1f, 1f, 0f, 0f);
vecValue = property.textureScaleAndOffset;
}
else
{
defaultVecValue = _shader.GetPropertyDefaultVectorValue(pack.index);
vecValue = property.vectorValue;
}
Vector2 defaultVecXYValue = new Vector2(defaultVecValue.x, defaultVecValue.y);
Vector2 defaultVecZWValue = new Vector2(defaultVecValue.z, defaultVecValue.w);
Vector2 vecXYValue = new Vector2(vecValue.x, vecValue.y);
Vector2 vecZWValue = new Vector2(vecValue.z, vecValue.w);
Vector2 defaultVecXYZValue = new Vector3(defaultVecValue.x, defaultVecValue.y,defaultVecValue.z);
Vector2 vecXYZValue = new Vector3(vecValue.x, vecValue.y,vecValue.z);
bool isVecModified = false;
switch (vectorValeType)
{
case VectorValeType.Undefine: Debug.LogError("VectorValeType is undefined"); break;
case VectorValeType.X: isVecModified = Mathf.Approximately(vecValue.x,defaultVecValue.x) ? false : true;break;
case VectorValeType.Y: isVecModified = Mathf.Approximately(vecValue.y,defaultVecValue.y) ? false : true;break;
case VectorValeType.Z: isVecModified = Mathf.Approximately(vecValue.z,defaultVecValue.z) ? false : true;break;
case VectorValeType.W: isVecModified = Mathf.Approximately(vecValue.w,defaultVecValue.w) ? false : true;break;
case VectorValeType.XY:case VectorValeType.Tilling:
isVecModified = vecXYValue == defaultVecXYValue ? false : true;break;
case VectorValeType.ZW:case VectorValeType.Offset:
isVecModified = vecZWValue == defaultVecZWValue ? false : true;break;
case VectorValeType.XYZ:isVecModified = vecXYZValue == defaultVecXYZValue ? false : true ; break;
case VectorValeType.XYZW:isVecModified= vecValue == defaultVecValue? false : true ; break;
}
return isVecModified;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Float or UnityEngine.Rendering.ShaderPropertyType.Range:
2025-08-27 21:45:18 -04:00
return Mathf.Approximately(property.floatValue, _shader.GetPropertyDefaultFloatValue(pack.index)) ? false : true;
2026-03-14 03:13:10 -04:00
case UnityEngine.Rendering.ShaderPropertyType.Texture:
2025-08-27 21:45:18 -04:00
if (property.textureValue == null)
{
return false;
}
else
{
return property.textureValue.name == "textureExternal" ? false : true;
}
// return property.textureValue.name == shader.GetPropertyTextureDefaultName(pack.index) ? false : true;
default:
// 如果不属于上述类型,输出提示信息
return false;
// Debug.Log($"{property.displayName} has no default value or unsupported type");
// break;
}
}
}
}