Files
ichni_Creator_Studio/Assets/Scripts/Graphical Tools/HSV Tool/HsvDrawer.cs

326 lines
10 KiB
C#
Raw Normal View History

using System.Collections;
using System.Collections.Generic;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public partial class HsvDrawer
{
[Header("Color Wheel Settings")]
public int textureSize = 256; // 纹理尺寸
public float saturation = 1f; // 最大饱和度
public float value = 1f; // 明度
[Header("Color Picker Settings")]
public RectTransform pickerIndicator; // 取色器指示器
public Color currentColor = Color.white; // 当前选中的颜色
public Slider valueSlider; // 亮度拖动条
public Slider alphaSlider; // 透明度拖动条
public RawImage previewImage; // 颜色预览窗
private Texture2D _texture;
public RawImage _rawImage;
private RectTransform _rectTransform;
public bool isEmission = false;
public GameObject emissionObj;
public InputField emissionInput;
public DynamicUIBaseColorPicker baseColorPicker;
void Start()
{
_rectTransform = _rawImage.GetComponent<RectTransform>(); // 初始化
CreateColorWheelTexture();
ApplyTextureToRawImage();
if (valueSlider != null)
{
valueSlider.minValue = 0f;
valueSlider.maxValue = 1f;
valueSlider.value = value;
valueSlider.onValueChanged.AddListener(OnValueSliderChanged);
}
if (alphaSlider != null)
{
alphaSlider.minValue = 0f;
alphaSlider.maxValue = 1f;
alphaSlider.onValueChanged.AddListener(OnAlphaSliderChanged);
}
if (previewImage != null)
{
previewImage.color = currentColor;
}
}
private Coroutine valueSliderCoroutine;
private float pendingValue = -1f;
// 新增:高低分辨率参数
public int highResTextureSize = 256;
public int lowResTextureSize = 64;
private bool isLowRes = false;
void OnValueSliderChanged(float newValue)
{
value = newValue;
pendingValue = newValue;
// 切换到低分辨率
if (!isLowRes)
{
isLowRes = true;
CreateColorWheelTexture(true);
ApplyTextureToRawImage();
}
if (valueSliderCoroutine != null)
StopCoroutine(valueSliderCoroutine);
valueSliderCoroutine = StartCoroutine(DelayedRedrawColorWheel());
// 刷新当前颜色
if (pickerIndicator != null)
UpdateCurrentColor(pickerIndicator.localPosition);
}
IEnumerator DelayedRedrawColorWheel()
{
float waitTime = 0.01f;
float timer = 0f;
while (timer < waitTime)
{
yield return null;
timer += Time.unscaledDeltaTime;
}
// 恢复高分辨率
if (isLowRes)
{
isLowRes = false;
CreateColorWheelTexture(false);
ApplyTextureToRawImage();
}
else
{
CreateColorWheelTexture(false);
ApplyTextureToRawImage();
}
valueSliderCoroutine = null;
}
void OnAlphaSliderChanged(float newAlpha)
{
// 只更新透明度
currentColor.a = newAlpha;
if (previewImage != null)
previewImage.color = currentColor;
}
void Update()
{
// 鼠标点击色轮区域即可拖动
if (Mouse.current.leftButton.wasPressedThisFrame && RectTransformUtility.RectangleContainsScreenPoint(_rectTransform, Mouse.current.position.ReadValue()))
{
StartCoroutine(DraggingColorPicker());
}
}
IEnumerator DraggingColorPicker()
{
while (Mouse.current.leftButton.isPressed)
{
Vector2 localPosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, Mouse.current.position.ReadValue(), null, out localPosition);
// 计算中心和最大半径
Vector2 center = _rectTransform.rect.center;
float maxRadius = _rectTransform.rect.width / 2f;
Vector2 offset = localPosition - center;
float distance = offset.magnitude;
// 如果超出圆形区域,则贴边
if (distance > maxRadius)
{
offset = offset.normalized * maxRadius;
localPosition = center + offset;
}
if (pickerIndicator != null)
pickerIndicator.localPosition = localPosition;
UpdateCurrentColor(localPosition);
yield return null; // 等待下一帧
}
}
// 整合分辨率逻辑到此方法
void CreateColorWheelTexture(bool useLowRes = false)
{
int targetSize = useLowRes ? lowResTextureSize : highResTextureSize;
textureSize = targetSize;
if (_texture == null || _texture.width != textureSize || _texture.height != textureSize)
_texture = new Texture2D(textureSize, textureSize, TextureFormat.RGBA32, false);
_texture.wrapMode = TextureWrapMode.Clamp;
Vector2 center = new Vector2(textureSize * 0.5f, textureSize * 0.5f);
float maxRadius = textureSize * 0.5f;
Color[] pixels = new Color[textureSize * textureSize];
for (int y = 0; y < textureSize; y++)
{
for (int x = 0; x < textureSize; x++)
{
Vector2 offset = new Vector2(x + 0.5f, y + 0.5f) - center;
float distance = offset.magnitude;
int idx = y * textureSize + x;
if (distance <= maxRadius)
{
float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg;
if (angle < 0) angle += 360f;
float sat = Mathf.Clamp01(distance / maxRadius) * saturation;
pixels[idx] = Color.HSVToRGB(angle / 360f, sat, value);
}
else
{
pixels[idx] = Color.clear;
}
}
}
_texture.SetPixels(pixels);
_texture.Apply();
}
void ApplyTextureToRawImage()
{
if (_rawImage == null)
_rawImage = GetComponent<RawImage>();
_rawImage.texture = _texture;
_rawImage.color = Color.white; // 确保显示原始颜色
}
void UpdateCurrentColor(Vector2 localPosition)
{
Vector2 center = _rectTransform.rect.center;
Vector2 offset = localPosition - center;
float maxRadius = _rectTransform.rect.width / 2f;
// 计算半径比例(饱和度)
float distance = offset.magnitude;
float sat = Mathf.Clamp01(distance / maxRadius) * saturation;
// 计算角度(色调)
float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg;
if (angle < 0) angle += 360;
// 计算颜色
float alpha = alphaSlider != null ? alphaSlider.value : 1f;
currentColor = Color.HSVToRGB(angle / 360f, sat, value);
currentColor.a = alpha;
// 更新取色器颜色(使其与背景有对比度)
if (pickerIndicator != null)
{
var img = pickerIndicator.GetComponent<Image>();
if (img != null)
img.color = (value > 0.5f) ? Color.black : Color.white;
}
// 若有亮度滑块,保持同步
if (valueSlider != null && valueSlider.value != value)
{
valueSlider.SetValueWithoutNotify(value);
}
// 若有透明度滑块,保持同步
if (alphaSlider != null && alphaSlider.value != alpha)
{
alphaSlider.SetValueWithoutNotify(alpha);
}
// 更新预览窗
if (previewImage != null)
{
previewImage.color = currentColor;
}
if (baseColorPicker != null)
{
// 同步到BaseColorPicker
baseColorPicker.SliderChangeWithoutNotification(currentColor);
}
ApplyParameters();
}
}
public partial class HsvDrawer : DynamicUIElement
{
private void ApplyParameters()
{
Color newValue = currentColor;
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newValue);
connectedBaseElement.Refresh();
}
// 新增同步connectedBaseElement的color到色盘
public void SyncFromBaseElement()
{
if (connectedBaseElement == null || string.IsNullOrEmpty(parameterName)) return;
Color color = (Color)connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement);
currentColor = color;
// 解析HSV
Color.RGBToHSV(color, out float h, out float s, out float v);
value = v;
if (valueSlider != null)
valueSlider.SetValueWithoutNotify(v);
if (alphaSlider != null)
alphaSlider.SetValueWithoutNotify(color.a);
// 计算picker位置
if (_rectTransform == null)
_rectTransform = _rawImage.GetComponent<RectTransform>();
Vector2 center = _rectTransform.rect.center;
float maxRadius = _rectTransform.rect.width / 2f;
float angle = h * 360f * Mathf.Deg2Rad;
float radius = s * maxRadius;
Vector2 offset = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
Vector2 pickerPos = center + offset;
if (pickerIndicator != null)
pickerIndicator.localPosition = pickerPos;
// 更新色盘和预览
CreateColorWheelTexture();
ApplyTextureToRawImage();
if (previewImage != null)
previewImage.color = currentColor;
}
public override void Initialize(IBaseElement baseElement, string title, string parameterName)
{
base.Initialize(baseElement, title, parameterName);
SyncFromBaseElement();
}
public override DynamicUIElement AddListenerFunction(UnityAction action)
{
valueSlider.onValueChanged.AddListener(_ => action());
alphaSlider.onValueChanged.AddListener(_ => action());
valueSlider.onValueChanged.AddListener(_ => UpdateCurrentColor(pickerIndicator.localPosition));
alphaSlider.onValueChanged.AddListener(_ => UpdateCurrentColor(pickerIndicator.localPosition));
// 拖动色盘时也触发
// 这里通过在 UpdateCurrentColor 里调用 action
// 但由于没有事件,这里可以考虑用委托或事件,但为兼容性直接调用
// 可以在 UpdateCurrentColor 末尾加一行(如果需要多次触发):
// action?.Invoke();
// 但一般只需响应滑块即可
return this;
}
}