Files
ichni_Creator_Studio/Packages/XuanXuanRenderUtility/Editor/ShaderGUIResetTool.cs
SoulliesOfficial aee62cd637 大修
2026-03-14 02:30:26 -04:00

399 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
UnityEngine.Rendering.ShaderPropertyType propertyType = property.propertyType;
if (pack.property.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture && vectorValeType != VectorValeType.Undefine)
{
propertyType = UnityEngine.Rendering.ShaderPropertyType.Vector;//Tilling or Offset
}
switch (propertyType)
{
case UnityEngine.Rendering.ShaderPropertyType.Color:
Vector4 colorValue = _shader.GetPropertyDefaultVectorValue(pack.index);
property.colorValue = new Color(colorValue.x, colorValue.y, colorValue.z, colorValue.x);
break;
case UnityEngine.Rendering.ShaderPropertyType.Vector:
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;
case UnityEngine.Rendering.ShaderPropertyType.Float or UnityEngine.Rendering.ShaderPropertyType.Range:
float value = _shader.GetPropertyDefaultFloatValue(pack.index);
property.floatValue = value;
break;
case UnityEngine.Rendering.ShaderPropertyType.Texture:
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;
UnityEngine.Rendering.ShaderPropertyType propertyType = property.propertyType;
if (pack.property.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture && vectorValeType != VectorValeType.Undefine)
{
propertyType = UnityEngine.Rendering.ShaderPropertyType.Vector;//Tilling or Offset
}
switch (propertyType)
{
case UnityEngine.Rendering.ShaderPropertyType.Color:
Vector4 colorValue = _shader.GetPropertyDefaultVectorValue(pack.index);
Color color = new Color(colorValue.x, colorValue.y, colorValue.z, colorValue.w);
return property.colorValue == color ? false : true;
case UnityEngine.Rendering.ShaderPropertyType.Vector:
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;
case UnityEngine.Rendering.ShaderPropertyType.Float or UnityEngine.Rendering.ShaderPropertyType.Range:
return Mathf.Approximately(property.floatValue, _shader.GetPropertyDefaultFloatValue(pack.index)) ? false : true;
case UnityEngine.Rendering.ShaderPropertyType.Texture:
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;
}
}
}
}