Files
ichni_Creator_Studio/Assets/Scripts/Graphical Tools/HSV Tool/HsvDrawer.cs
TRAfoer f965857267 FiX
Signed-off-by: TRAfoer <lhf190@outlook.com>
2025-07-16 11:20:17 +08:00

283 lines
9.4 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;
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;
}
}
void OnValueSliderChanged(float newValue)
{
value = newValue;
CreateColorWheelTexture();
ApplyTextureToRawImage();
// 刷新当前颜色
if (pickerIndicator != null)
UpdateCurrentColor(pickerIndicator.localPosition);
}
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()
{
// 创建方形纹理
_texture = new Texture2D(textureSize, textureSize, TextureFormat.RGBA32, false);
_texture.wrapMode = TextureWrapMode.Clamp;
Vector2 center = new Vector2(textureSize / 2f, textureSize / 2f);
float maxRadius = textureSize / 2f;
// 遍历所有像素
for (int y = 0; y < textureSize; y++)
{
for (int x = 0; x < textureSize; x++)
{
Vector2 pixelPos = new Vector2(x, y);
Vector2 offset = pixelPos - center;
float distance = offset.magnitude;
// 在圆形区域内绘制
if (distance <= maxRadius)
{
// 计算角度0-360°
float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg;
if (angle < 0) angle += 360;
// 计算饱和度(基于半径比例)
float sat = Mathf.Clamp01(distance / maxRadius) * saturation;
// HSV转RGB
Color color = Color.HSVToRGB(angle / 360f, sat, value);
_texture.SetPixel(x, y, color);
}
else
{
// 圆形外透明
_texture.SetPixel(x, y, Color.clear);
}
}
}
_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.SliderChangeWithoutNofication(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;
}
}