Files
ichni_Official/Packages/NB_FX/XuanXuanRenderUtility/Editor/ShaderGUIItems/ShaderGUIFloatItem.cs
SoulliesOfficial 40fa80cd70 NB_FX
2026-07-17 17:46:16 -04:00

395 lines
14 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;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
public class ShaderGUIFloatItem:ShaderGUIItem
{
private readonly Func<bool> _isVisible;
public ShaderGUIFloatItem(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem, Func<bool> isVisible = null) :
base(rootItem, parentItem: parentItem)
{
_isVisible = isVisible;
base.InitTriggerByChild();
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
return;
}
base.OnGUI();
}
public override void DrawController()
{
float value = DraggableLabelFloat.Handle(LabelRect, PropertyInfo.Property.floatValue, sensitivity: -1f);//拖动Label控件可以操作Float参数
value = EditorGUI.FloatField(ControlRect, value);
SetFloatIfDifferent(PropertyInfo.Property, value);
}
}
public class ShaderGUISliderItem:ShaderGUIItem
{
public float Min = 0;
public float Max = 1;
public string RangePropertyName;
ShaderPropertyInfo _rangePropertyInfo;
private readonly Func<bool> _isVisible;
private const float SliderFrontGap = 5f;
private const float SliderBackGap = 2f;
private const float RangeFieldWidth = 30f;
public override void InitTriggerByChild()
{
if (RangePropertyName != null)
{
_rangePropertyInfo = RootItem.PropertyInfoDic[RangePropertyName];
Min = _rangePropertyInfo.Property.vectorValue.x;
Max = _rangePropertyInfo.Property.vectorValue.y;
}
base.InitTriggerByChild();
}
public ShaderGUISliderItem(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem, Func<bool> isVisible = null) :
base(rootItem, parentItem: parentItem)
{
_isVisible = isVisible;
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
return;
}
if (_rangePropertyInfo == null)
{
base.OnGUI();
return;
}
GetRect();
using (ParentControlDisabledScope())
{
EditorGUI.LabelField(LabelRect, GuiContent);
}
using (ParentControlDisabledScope())
{
EditorGUI.BeginChangeCheck();
using (new EditorGUIIndentLevelScope(0))
{
DrawController();
}
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
OnEndChange();
}
}
DrawResetButton();
DrawBlock();
}
public override void DrawController()
{
if (_rangePropertyInfo != null)
{
Rect minRect = ControlRect;
minRect.width = RangeFieldWidth;
Rect maxRect = ControlRect;
maxRect.x = ControlRect.xMax - RangeFieldWidth;
maxRect.width = RangeFieldWidth;
Rect sliderRect = ControlRect;
sliderRect.x = minRect.xMax + SliderFrontGap;
sliderRect.width = Mathf.Max(0f, maxRect.x - sliderRect.x - SliderBackGap + EditorGUI.indentLevel * UnityEditorGUIIndentWidth);
RangeVecHasMixedValue(out bool minValueHasMixed,out bool maxValueHasMixed);
Vector4 rangeVector = _rangePropertyInfo.Property.vectorValue;
float min = rangeVector.x;
float max = rangeVector.y;
EditorGUI.showMixedValue = minValueHasMixed;
bool minAnimatedScope = BeginAnimatedPropertyBackground(minRect, _rangePropertyInfo.Property);
min = EditorGUI.FloatField(minRect, min);
EndAnimatedPropertyBackground(minAnimatedScope);
EditorGUI.showMixedValue = maxValueHasMixed;
bool maxAnimatedScope = BeginAnimatedPropertyBackground(maxRect, _rangePropertyInfo.Property);
max = EditorGUI.FloatField(maxRect, max);
EndAnimatedPropertyBackground(maxAnimatedScope);
rangeVector.x = min;
rangeVector.y = max;
SetVectorIfDifferent(_rangePropertyInfo.Property, rangeVector);
float sliderMin = Mathf.Min(min, max);
float sliderMax = Mathf.Max(min, max);
float value = DraggableLabelFloat.Handle(
LabelRect,
PropertyInfo.Property.floatValue,
DraggableLabelFloat.GetSensitivityByRange(sliderMin, sliderMax),
sliderMin,
sliderMax);
EditorGUI.showMixedValue = PropertyInfo.Property.hasMixedValue;
bool sliderAnimatedScope = BeginAnimatedPropertyBackground(sliderRect, PropertyInfo.Property);
value = SliderNoIndent(sliderRect, value, sliderMin, sliderMax);
EndAnimatedPropertyBackground(sliderAnimatedScope);
SetFloatIfDifferent(PropertyInfo.Property, Mathf.Clamp(value, sliderMin, sliderMax));
EditorGUI.showMixedValue = false;
}
else
{
float value = DraggableLabelFloat.Handle(
LabelRect,
PropertyInfo.Property.floatValue,
DraggableLabelFloat.GetSensitivityByRange(Min, Max),
Min,
Max);
value = EditorGUI.Slider(ControlRect, value,Min,Max);
SetFloatIfDifferent(PropertyInfo.Property, value);
}
}
private static float SliderNoIndent(Rect rect, float value, float min, float max)
{
int indentLevel = EditorGUI.indentLevel;
try
{
EditorGUI.indentLevel = 0;
return EditorGUI.Slider(rect, value, min, max);
}
finally
{
EditorGUI.indentLevel = indentLevel;
}
}
void RangeVecHasMixedValue( out bool minValueHasMixed, out bool maxValueHasMixed)
{
minValueHasMixed = false;
maxValueHasMixed = false;
if (RootItem.Mats.Count > 1)
{
MaterialProperty rangeProperty = _rangePropertyInfo.Property;
float minValue = 0;
float maxValue = 0;
for (int i = 0; i < RootItem.Mats.Count; i++)
{
Vector4 rangeVec = RootItem.Mats[i].GetVector(RangePropertyName);
if (i == 0)
{
minValue = rangeVec.x;
maxValue = rangeVec.y;
}
else
{
if (!Mathf.Approximately(minValue, rangeVec.x))
{
minValueHasMixed = true;
}
if (!Mathf.Approximately(maxValue, rangeVec.y))
{
maxValueHasMixed = true;
}
}
}
}
}
bool RangePropIsDefaultValue()
{
MaterialProperty rangeProperty = _rangePropertyInfo.Property;
return rangeProperty.vectorValue == RootItem.Shader.GetPropertyDefaultVectorValue(_rangePropertyInfo.Index) && !rangeProperty.hasMixedValue;
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
if (RangePropertyName != null)
{
if (!isCallByChild) //只有自身Reset了才需要查询自己的状态是否正确
{
bool isDefaultValue = true;
float defaultValue = RootItem.Shader.GetPropertyDefaultFloatValue(PropertyInfo.Index);
isDefaultValue = Mathf.Approximately(PropertyInfo.Property.floatValue, defaultValue);
Vector4 defaultRangeVec = RootItem.Shader.GetPropertyDefaultVectorValue(_rangePropertyInfo.Index);
isDefaultValue &= _rangePropertyInfo.Property.vectorValue == defaultRangeVec;
base.CheckIsPropertyModified(isCallByChild);
if (isDefaultValue == PropertyIsDefaultValue)
{
return; //如果状态没有改变,就不需要做任何操作
}
else
{
PropertyIsDefaultValue = isDefaultValue;
}
}
HasModified = !PropertyIsDefaultValue;
foreach (var childItem in ChildrenItemList)
{
HasModified |= childItem.HasModified;
}
ParentItem?.CheckIsPropertyModified(true);
}
else
{
base.CheckIsPropertyModified(isCallByChild);
}
}
public override void ExecuteReset(bool isCallByParent = false)
{
if (RangePropertyName != null)
{
PropertyInfo.Property.floatValue = RootItem.Shader.GetPropertyDefaultFloatValue(PropertyInfo.Index);
_rangePropertyInfo.Property.vectorValue =
RootItem.Shader.GetPropertyDefaultVectorValue(_rangePropertyInfo.Index);
PropertyIsDefaultValue = true;
foreach (var childItem in ChildrenItemList)
{
childItem.ExecuteReset(true);
}
HasModified = false;
if (!isCallByParent) //直接由用户触发重置
{
ParentItem?.CheckIsPropertyModified(true);
}
}
else
{
base.ExecuteReset(isCallByParent);
}
}
}
//用于滑动控制Label的方案。
// DraggableLabelFloat.cs
public static class DraggableLabelFloat
{
// 为每个控件实例缓存一次拖拽状态
private static readonly System.Collections.Generic.Dictionary<int, DragState> s_Drag =
new System.Collections.Generic.Dictionary<int, DragState>();
private class DragState
{
public float startValue;
public float dragX; // 累计水平位移(单位:像素)
}
public static float Handle(Rect labelRect, float value, float sensitivity = -1f, float? min = null, float? max = null)
{
if (!GUI.enabled)
{
return value;
}
EditorGUIUtility.AddCursorRect(labelRect, MouseCursor.SlideArrow);
int id = GUIUtility.GetControlID(FocusType.Passive, labelRect);
Event e = Event.current;
switch (e.GetTypeForControl(id))
{
case EventType.MouseDown:
if (labelRect.Contains(e.mousePosition) && e.button == 0)
{
GUIUtility.hotControl = id;
e.Use();
EditorGUIUtility.SetWantsMouseJumping(1);
s_Drag[id] = new DragState
{
startValue = value,
dragX = 0f
};
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == id && s_Drag.TryGetValue(id, out var st))
{
// 关键:使用 Event.delta 累加位移,兼容越界/跳回
st.dragX += e.delta.x;
float baseSens = sensitivity > 0f
? sensitivity
: 0.003f * Mathf.Max(1f, Mathf.Abs(st.startValue));
float modifier = 1f;
if (e.shift) modifier *= 0.1f;
if (e.control || e.command) modifier *= 10f;
float accel = 1f + 0.15f * Mathf.Clamp01(Mathf.Abs(st.dragX) / 50f);
float newValue = st.startValue + st.dragX * baseSens * modifier * accel;
if (min.HasValue) newValue = Mathf.Max(min.Value, newValue);
if (max.HasValue) newValue = Mathf.Min(max.Value, newValue);
if (!float.IsNaN(newValue) && !float.IsInfinity(newValue) && !Mathf.Approximately(newValue, value))
{
GUI.changed = true;
value = newValue;
}
e.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == id)
{
GUIUtility.hotControl = 0;
EditorGUIUtility.SetWantsMouseJumping(0);
s_Drag.Remove(id);
e.Use();
}
break;
case EventType.KeyDown:
// 可选ESC 取消拖拽并还原
if (GUIUtility.hotControl == id && e.keyCode == KeyCode.Escape && s_Drag.TryGetValue(id, out var st2))
{
value = st2.startValue;
GUI.changed = true;
GUIUtility.hotControl = 0;
EditorGUIUtility.SetWantsMouseJumping(0);
s_Drag.Remove(id);
e.Use();
}
break;
}
return value;
}
public static float GetSensitivityByRange(float min, float max)
{
float range = Mathf.Abs(max - min);
if (float.IsNaN(range) || float.IsInfinity(range) || Mathf.Approximately(range, 0f))
{
return -1f;
}
return range * 0.003f;
}
}
}