587 lines
23 KiB
C#
587 lines
23 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using Sirenix.OdinInspector;
|
||
using System.Linq;
|
||
using UnityEngine.InputSystem;
|
||
using Michsky.MUIP;
|
||
|
||
#if UNITY_EDITOR
|
||
using UnityEditor;
|
||
#endif
|
||
|
||
namespace Ichni.Editor
|
||
{
|
||
[RequireComponent(typeof(RawImage))]
|
||
public class KeyframeVisualizer : MonoBehaviour
|
||
{
|
||
public AnimationCurve curve;
|
||
public float timeRange = 10f;
|
||
public float valueRange = 10f;
|
||
public float keyframeSize = 0.2f;
|
||
public float tangentLength = 1f;
|
||
public Color curveColor = Color.green;
|
||
public Color keyframeColor = Color.red;
|
||
public Color tangentColor = Color.blue;
|
||
public int segments = 5;
|
||
|
||
[Header("Curve Preview")]
|
||
public RawImage curveRawImage;
|
||
public Vector2Int curveTextureSize = new Vector2Int(256, 128);
|
||
|
||
[System.Serializable]
|
||
public struct KeyframeImageInfo
|
||
{
|
||
public Image keyImage;
|
||
public Image inTangentImage;
|
||
public Image outTangentImage;
|
||
}
|
||
|
||
public List<KeyframeImageInfo> keyframeImages = new List<KeyframeImageInfo>();
|
||
|
||
// 合并min/max到类成员,便于全局一致使用
|
||
private float minTime, maxTime, minValue = 0f, maxValue = 1f;
|
||
|
||
private void UpdateCurveRange()
|
||
{
|
||
if (curve == null || curve.length < 2)
|
||
{
|
||
minTime = maxTime = valueRange = timeRange = 0;
|
||
minValue = 0f;
|
||
maxValue = 1f;
|
||
return;
|
||
}
|
||
minTime = 0f;
|
||
maxTime = 1f;
|
||
minValue = 0f; // 固定下界为0
|
||
maxValue = 1f; // 固定上界为1
|
||
valueRange = Mathf.Max(0.0001f, maxValue - minValue);
|
||
timeRange = Mathf.Max(0.0001f, maxTime - minTime);
|
||
}
|
||
|
||
[Button("Draw Curve To RawImage")]
|
||
public void DrawCurveToRawImage()
|
||
{
|
||
UpdateCurveRange();
|
||
if (curveRawImage == null || curve == null || curve.length < 2) return;
|
||
|
||
int texWidth = curveTextureSize.x;
|
||
int texHeight = curveTextureSize.y;
|
||
Texture2D tex = new Texture2D(texWidth, texHeight, TextureFormat.ARGB32, false);
|
||
tex.filterMode = FilterMode.Point;
|
||
tex.wrapMode = TextureWrapMode.Clamp;
|
||
|
||
// 清空
|
||
for (int i = 0; i < texWidth; i++)
|
||
for (int j = 0; j < texHeight; j++)
|
||
tex.SetPixel(i, j, new Color(0, 0, 0, 0));
|
||
|
||
// === 新增:绘制网格 ===
|
||
int gridXCount = 8;
|
||
int gridYCount = 4;
|
||
Color gridColor = new Color(0.3f, 0.3f, 0.3f, 0.7f);
|
||
for (int gx = 1; gx < gridXCount; gx++)
|
||
{
|
||
int x = gx * texWidth / gridXCount;
|
||
DrawVerticalLineOnTexture(tex, x, 0, texHeight - 1, gridColor);
|
||
}
|
||
for (int gy = 1; gy < gridYCount; gy++)
|
||
{
|
||
int y = gy * texHeight / gridYCount;
|
||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, y, gridColor);
|
||
}
|
||
|
||
// === 新增:绘制边框 ===
|
||
Color borderColor = Color.white;
|
||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, 0, borderColor);
|
||
DrawHorizontalLineOnTexture(tex, 0, texWidth - 1, texHeight - 1, borderColor);
|
||
DrawVerticalLineOnTexture(tex, 0, 0, texHeight - 1, borderColor);
|
||
DrawVerticalLineOnTexture(tex, texWidth - 1, 0, texHeight - 1, borderColor);
|
||
|
||
int lastY = -1;
|
||
for (int x = 0; x < texWidth; x++)
|
||
{
|
||
float t = (float)x / (texWidth - 1);
|
||
float time = Mathf.Lerp(minTime, maxTime, t);
|
||
float value = curve.Evaluate(time);
|
||
float normY = (value - minValue) / valueRange;
|
||
int y = (int)(normY * (texHeight - 1));
|
||
|
||
bool outOfRange = y < 0 || y >= texHeight;
|
||
int drawY = y;
|
||
|
||
Color drawColor = outOfRange
|
||
? new Color(1f - curveColor.r, 1f - curveColor.g, 1f - curveColor.b, 1f)
|
||
: curveColor;
|
||
|
||
if (lastY >= 0)
|
||
{
|
||
int y0 = lastY;
|
||
int y1 = y;
|
||
int x0 = x - 1;
|
||
int x1 = x;
|
||
// === 修正:补全断点 ===
|
||
if (x0 >= 0 && x0 < texWidth && x1 >= 0 && x1 < texWidth)
|
||
{
|
||
if (Mathf.Abs(y1 - y0) > 1)
|
||
{
|
||
int step = y1 > y0 ? 1 : -1;
|
||
for (int yyy = y0; yyy != y1; yyy += step)
|
||
{
|
||
if (yyy >= 0 && yyy < texHeight)
|
||
tex.SetPixel(x0, yyy, curveColor);
|
||
}
|
||
}
|
||
}
|
||
int dy = Mathf.Abs(y1 - y0);
|
||
int sy = y0 < y1 ? 1 : -1;
|
||
int err = dy / 2;
|
||
int yy = y0;
|
||
for (int xx = x0; xx <= x1; xx++)
|
||
{
|
||
bool segOutOfRange = yy < 0 || yy >= texHeight;
|
||
Color segColor = segOutOfRange
|
||
? new Color(1f - curveColor.r, 1f - curveColor.g, 1f - curveColor.b, 1f)
|
||
: curveColor;
|
||
if (xx >= 0 && xx < texWidth)
|
||
{
|
||
for (int j = lastY; j < yy; j++) tex.SetPixel(x0, j, curveColor);
|
||
for (int j = lastY; j > yy; j--) tex.SetPixel(x0, j, curveColor);
|
||
tex.SetPixel(xx, yy, segColor);
|
||
}
|
||
err -= dy;
|
||
if (err < 0)
|
||
{
|
||
yy += sy;
|
||
err += (x1 - x0);
|
||
}
|
||
}
|
||
}
|
||
if (x >= 0 && x < texWidth)
|
||
tex.SetPixel(x, drawY, drawColor);
|
||
|
||
lastY = y;
|
||
}
|
||
|
||
foreach (var key in curve.keys)
|
||
{
|
||
float tangentScale = (maxTime - minTime) * 0.08f;
|
||
if (!float.IsInfinity(key.inTangent))
|
||
{
|
||
float t0 = key.time;
|
||
float v0 = key.value;
|
||
float t1 = t0 - tangentScale;
|
||
float v1 = v0 - key.inTangent * tangentScale;
|
||
int x0 = (int)(((t0 - minTime) / timeRange) * (texWidth - 1));
|
||
int y0 = (int)(((v0 - minValue) / valueRange) * (texHeight - 1));
|
||
int x1 = (int)(((t1 - minTime) / timeRange) * (texWidth - 1));
|
||
int y1 = (int)(((v1 - minValue) / valueRange) * (texHeight - 1));
|
||
DrawLineOnTexture(tex, x0, y0, x1, y1, tangentColor);
|
||
}
|
||
if (!float.IsInfinity(key.outTangent))
|
||
{
|
||
float t0 = key.time;
|
||
float v0 = key.value;
|
||
float t1 = t0 + tangentScale;
|
||
float v1 = v0 + key.outTangent * tangentScale;
|
||
int x0 = (int)(((t0 - minTime) / timeRange) * (texWidth - 1));
|
||
int y0 = (int)(((v0 - minValue) / valueRange) * (texHeight - 1));
|
||
int x1 = (int)(((t1 - minTime) / timeRange) * (texWidth - 1));
|
||
int y1 = (int)(((v1 - minValue) / valueRange) * (texHeight - 1));
|
||
DrawLineOnTexture(tex, x0, y0, x1, y1, tangentColor * 0.8f);
|
||
}
|
||
}
|
||
|
||
tex.Apply();
|
||
curveRawImage.texture = tex;
|
||
}
|
||
|
||
private void DrawLineOnTexture(Texture2D tex, int x0, int y0, int x1, int y1, Color color)
|
||
{
|
||
int dx = Mathf.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||
int dy = Mathf.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||
int err = (dx > dy ? dx : -dy) / 2, e2;
|
||
int lastY = y0;
|
||
while (true)
|
||
{
|
||
for (int j = lastY; j < y0; j++) tex.SetPixel(x0, j, color);
|
||
for (int j = lastY; j > y0; j--) tex.SetPixel(x0, j, color);
|
||
tex.SetPixel(x0, y0, color);
|
||
lastY = y0;
|
||
if (x0 == x1 && y0 == y1) break;
|
||
e2 = err;
|
||
if (e2 > -dx) { err -= dy; x0 += sx; }
|
||
if (e2 < dy) { err += dx; y0 += sy; }
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取关键帧在RawImage中的localPosition(以RawImage中心为原点)
|
||
/// </summary>
|
||
public Vector2 GetKeyframeLocalPositionInRawImage(Keyframe key, float scale = 1f)
|
||
{
|
||
UpdateCurveRange();
|
||
if (curveRawImage == null || curve == null || curve.length < 2)
|
||
return Vector2.zero;
|
||
|
||
// 这里直接使用固定的minValue/maxValue
|
||
float normX = (key.time - minTime) / timeRange;
|
||
float normY = (key.value - 0f) / Mathf.Max(0.0001f, 1f - 0f);
|
||
|
||
float px = normX * curveTextureSize.x;
|
||
float py = normY * curveTextureSize.y;
|
||
|
||
Vector2 localPos = new Vector2(
|
||
px - curveTextureSize.x * 0.5f,
|
||
py - curveTextureSize.y * 0.5f
|
||
);
|
||
return localPos * scale;
|
||
}
|
||
|
||
[Button("Create Keyframe Images")]
|
||
public void CreateKeyframeImages()
|
||
{
|
||
UpdateCurveRange();
|
||
if (curveRawImage == null || curve == null || curve.length < 1) return;
|
||
|
||
for (int i = curveRawImage.transform.childCount - 1; i >= 0; i--)
|
||
{
|
||
var child = curveRawImage.transform.GetChild(i);
|
||
#if UNITY_EDITOR
|
||
if (!Application.isPlaying)
|
||
DestroyImmediate(child.gameObject);
|
||
else
|
||
#endif
|
||
Destroy(child.gameObject);
|
||
}
|
||
keyframeImages.Clear();
|
||
|
||
for (int i = 0; i < curve.length; i++)
|
||
{
|
||
Keyframe key = curve.keys[i];
|
||
Vector2 localPos = GetKeyframeLocalPositionInRawImage(key);
|
||
|
||
GameObject go = new GameObject($"KeyframeImage_{i}", typeof(RectTransform), typeof(Image));
|
||
go.transform.SetParent(curveRawImage.transform, false);
|
||
|
||
RectTransform rt = go.GetComponent<RectTransform>();
|
||
rt.sizeDelta = Vector2.one * 16f;
|
||
rt.anchoredPosition = localPos;
|
||
|
||
Image img = go.GetComponent<Image>();
|
||
img.color = keyframeColor;
|
||
img.raycastTarget = false;
|
||
PointMover pointMover = go.AddComponent<PointMover>();
|
||
pointMover.parent = this;
|
||
pointMover.keyIndex = i;
|
||
|
||
Image inImg = null;
|
||
if (!float.IsInfinity(key.inTangent))
|
||
{
|
||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, true);
|
||
GameObject tgo = new GameObject($"TangentInImage_{i}", typeof(RectTransform), typeof(Image));
|
||
tgo.transform.SetParent(curveRawImage.transform, false);
|
||
RectTransform trt = tgo.GetComponent<RectTransform>();
|
||
trt.sizeDelta = Vector2.one * 10f;
|
||
trt.anchoredPosition = tangentLocalPos;
|
||
inImg = tgo.GetComponent<Image>();
|
||
inImg.color = tangentColor;
|
||
inImg.raycastTarget = false;
|
||
PointMover pointMover1 = tgo.AddComponent<PointMover>();
|
||
pointMover1.IO = 1;
|
||
pointMover1.parent = this;
|
||
pointMover1.keyIndex = i;
|
||
pointMover.subpointMover.Add(pointMover1);
|
||
}
|
||
|
||
Image outImg = null;
|
||
if (!float.IsInfinity(key.outTangent))
|
||
{
|
||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, false);
|
||
GameObject tgo = new GameObject($"TangentOutImage_{i}", typeof(RectTransform), typeof(Image));
|
||
tgo.transform.SetParent(curveRawImage.transform, false);
|
||
RectTransform trt = tgo.GetComponent<RectTransform>();
|
||
trt.sizeDelta = Vector2.one * 10f;
|
||
trt.anchoredPosition = tangentLocalPos;
|
||
outImg = tgo.GetComponent<Image>();
|
||
outImg.color = tangentColor * 0.8f;
|
||
outImg.raycastTarget = false;
|
||
PointMover pointMover2 = tgo.AddComponent<PointMover>();
|
||
pointMover2.IO = -1;
|
||
pointMover2.parent = this;
|
||
pointMover2.keyIndex = i;
|
||
pointMover.subpointMover.Add(pointMover2);
|
||
}
|
||
|
||
keyframeImages.Add(new KeyframeImageInfo
|
||
{
|
||
keyImage = img,
|
||
inTangentImage = inImg,
|
||
outTangentImage = outImg
|
||
});
|
||
}
|
||
}
|
||
|
||
// 修复后的切线位置计算方法
|
||
private Vector2 GetTangentLocalPosition(Keyframe key, bool isIn)
|
||
{
|
||
Vector2 keyLocalPos = GetKeyframeLocalPositionInRawImage(key);
|
||
float tangent = isIn ? key.inTangent : key.outTangent;
|
||
|
||
// 计算像素/单位转换比例
|
||
float pixelsPerTimeUnit = curveTextureSize.x / timeRange;
|
||
float pixelsPerValueUnit = curveTextureSize.y / valueRange;
|
||
|
||
// 处理无穷斜率的情况(垂直切线)
|
||
if (float.IsInfinity(tangent))
|
||
{
|
||
return keyLocalPos + new Vector2(
|
||
0,
|
||
isIn ? -tangentLength * 20f : tangentLength * 20f
|
||
);
|
||
}
|
||
|
||
// 计算方向向量
|
||
Vector2 direction = new Vector2(
|
||
isIn ? -1f : 1f,
|
||
tangent * (pixelsPerValueUnit / pixelsPerTimeUnit)
|
||
).normalized;
|
||
|
||
// 动态计算像素长度
|
||
float dynamicLength = tangentLength * Mathf.Min(curveTextureSize.x, curveTextureSize.y) * 0.1f;
|
||
|
||
return keyLocalPos + direction * dynamicLength;
|
||
}
|
||
[Button("Update Curve From Images")]
|
||
public void UpdateCurveFromImages()
|
||
{
|
||
UpdateCurveRange();
|
||
if (curve == null || keyframeImages == null || keyframeImages.Count < curve.length) return;
|
||
|
||
Keyframe[] newKeys = new Keyframe[curve.length];
|
||
for (int i = 0; i < curve.length; i++)
|
||
{
|
||
RectTransform rt = keyframeImages[i].keyImage.rectTransform;
|
||
Vector2 localPos = rt.anchoredPosition;
|
||
float px = localPos.x + curveTextureSize.x * 0.5f;
|
||
float py = localPos.y + curveTextureSize.y * 0.5f;
|
||
float normX = px / curveTextureSize.x;
|
||
float normY = py / curveTextureSize.y;
|
||
float time = Mathf.Lerp(minTime, maxTime, normX);
|
||
float value = Mathf.Clamp01(0f + normY * Mathf.Max(0.0001f, 1f - 0f));
|
||
|
||
float inTangent = curve.keys[i].inTangent;
|
||
float outTangent = curve.keys[i].outTangent;
|
||
float timeScale = timeRange / curveTextureSize.x;
|
||
float valueScale = valueRange / curveTextureSize.y;
|
||
|
||
// 修复切线斜率计算
|
||
if (keyframeImages[i].inTangentImage != null)
|
||
{
|
||
Vector2 inLocalPos = keyframeImages[i].inTangentImage.rectTransform.anchoredPosition;
|
||
Vector2 keyLocalPos = keyframeImages[i].keyImage.rectTransform.anchoredPosition;
|
||
|
||
// 使用像素坐标差计算真实斜率
|
||
float dx = (keyLocalPos.x - inLocalPos.x) * timeScale;
|
||
float dy = (keyLocalPos.y - inLocalPos.y) * valueScale;
|
||
|
||
if (Mathf.Abs(dx) > 0.001f)
|
||
inTangent = dy / dx;
|
||
}
|
||
|
||
if (keyframeImages[i].outTangentImage != null)
|
||
{
|
||
Vector2 outLocalPos = keyframeImages[i].outTangentImage.rectTransform.anchoredPosition;
|
||
Vector2 keyLocalPos = keyframeImages[i].keyImage.rectTransform.anchoredPosition;
|
||
|
||
// 使用像素坐标差计算真实斜率
|
||
float dx = (outLocalPos.x - keyLocalPos.x) * timeScale;
|
||
float dy = (outLocalPos.y - keyLocalPos.y) * valueScale;
|
||
|
||
if (Mathf.Abs(dx) > 0.001f)
|
||
outTangent = dy / dx;
|
||
}
|
||
|
||
Keyframe newKey = new Keyframe(time, value, inTangent, outTangent);
|
||
newKeys[i] = newKey;
|
||
}
|
||
curve.keys = newKeys;
|
||
}
|
||
|
||
[Button("Refresh Keyframe Images Position")]
|
||
public void RefreshKeyframeImagesPosition()
|
||
{
|
||
UpdateCurveRange();
|
||
if (curve == null || keyframeImages == null || keyframeImages.Count < curve.length) return;
|
||
|
||
for (int i = 0; i < curve.length; i++)
|
||
{
|
||
Keyframe key = curve.keys[i];
|
||
var info = keyframeImages[i];
|
||
|
||
if (info.keyImage != null)
|
||
{
|
||
Vector2 localPos = GetKeyframeLocalPositionInRawImage(key);
|
||
info.keyImage.rectTransform.anchoredPosition = localPos;
|
||
}
|
||
|
||
if (info.inTangentImage != null && !float.IsInfinity(key.inTangent))
|
||
{
|
||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, true);
|
||
info.inTangentImage.rectTransform.anchoredPosition = tangentLocalPos;
|
||
}
|
||
|
||
if (info.outTangentImage != null && !float.IsInfinity(key.outTangent))
|
||
{
|
||
Vector2 tangentLocalPos = GetTangentLocalPosition(key, false);
|
||
info.outTangentImage.rectTransform.anchoredPosition = tangentLocalPos;
|
||
}
|
||
}
|
||
}
|
||
|
||
public CompositeParameterWindow compositeParameterWindow;
|
||
public void UpadteValue()
|
||
{
|
||
compositeParameterWindow.connectedBaseElement.GetType().GetField(compositeParameterWindow.parameterName).SetValue(compositeParameterWindow.connectedBaseElement, curve);
|
||
}
|
||
|
||
// === 新增:绘制水平线辅助方法 ===
|
||
private void DrawHorizontalLineOnTexture(Texture2D tex, int x0, int x1, int y, Color color)
|
||
{
|
||
int width = tex.width;
|
||
int height = tex.height;
|
||
if (y < 0 || y >= height) return;
|
||
int minX = Mathf.Clamp(Mathf.Min(x0, x1), 0, width - 1);
|
||
int maxX = Mathf.Clamp(Mathf.Max(x0, x1), 0, width - 1);
|
||
for (int x = minX; x <= maxX; x++)
|
||
tex.SetPixel(x, y, color);
|
||
}
|
||
|
||
// === 新增:绘制垂直线辅助方法 ===
|
||
private void DrawVerticalLineOnTexture(Texture2D tex, int x, int y0, int y1, Color color)
|
||
{
|
||
int width = tex.width;
|
||
int height = tex.height;
|
||
if (x < 0 || x >= width) return;
|
||
int minY = Mathf.Clamp(Mathf.Min(y0, y1), 0, height - 1);
|
||
int maxY = Mathf.Clamp(Mathf.Max(y0, y1), 0, height - 1);
|
||
for (int y = minY; y <= maxY; y++)
|
||
tex.SetPixel(x, y, color);
|
||
}
|
||
}
|
||
|
||
public class PointMover : MonoBehaviour
|
||
{
|
||
|
||
public RectTransform rectTransform;
|
||
public KeyframeVisualizer parent;
|
||
public int keyIndex = -1; // 记录所属关键帧索引
|
||
public PointMover parentPointMover;
|
||
public List<PointMover> subpointMover = new();
|
||
public bool Pressed;
|
||
public int IO = 0;//0关键帧 1in -1out
|
||
|
||
private Dictionary<PointMover, Vector2> initialOffsets; // 存储切线点初始偏移
|
||
private Vector2 startPosition; // 拖拽开始位置
|
||
|
||
private void Start()
|
||
{
|
||
rectTransform = gameObject.GetComponent<RectTransform>();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Mouse.current.position.ReadValue()))
|
||
{
|
||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||
{
|
||
StartCoroutine(Moving());
|
||
}
|
||
}
|
||
}
|
||
|
||
public IEnumerator Moving()
|
||
{
|
||
var windowDragger = parent.compositeParameterWindow.GetComponent<WindowDragger>();
|
||
if (windowDragger != null)
|
||
{
|
||
windowDragger.Lock = true;
|
||
}
|
||
|
||
// 获取边界尺寸
|
||
float halfWidth = parent.curveTextureSize.x * 0.5f;
|
||
float halfHeight = parent.curveTextureSize.y * 0.5f;
|
||
|
||
// 如果是切线点,记录初始位置和方向
|
||
Vector2 initialPosition = rectTransform.anchoredPosition;
|
||
Vector2 initialDirection = Vector2.zero;
|
||
if (IO != 0)
|
||
{
|
||
PointMover keyPoint = parentPointMover != null ? parentPointMover : this;
|
||
Vector2 keyPos = keyPoint.rectTransform.anchoredPosition;
|
||
initialDirection = (initialPosition - keyPos).normalized;
|
||
}
|
||
|
||
while (Mouse.current.leftButton.isPressed)
|
||
{
|
||
Vector2 mouseDelta = Mouse.current.delta.ReadValue();
|
||
Vector2 newPos = rectTransform.anchoredPosition + mouseDelta;
|
||
|
||
// 边界约束
|
||
newPos.x = Mathf.Clamp(newPos.x, -halfWidth, halfWidth);
|
||
newPos.y = Mathf.Clamp(newPos.y, -halfHeight, halfHeight);
|
||
|
||
// 如果是切线点,约束移动方向
|
||
if (IO != 0 && initialDirection != Vector2.zero)
|
||
{
|
||
Vector2 keyPos = parentPointMover.rectTransform.anchoredPosition;
|
||
Vector2 toNewPos = newPos - keyPos;
|
||
|
||
// 计算与初始方向的夹角
|
||
float angle = Vector2.Angle(initialDirection, toNewPos);
|
||
|
||
// 如果偏离初始方向超过45度,修正方向
|
||
if (angle > 45f)
|
||
{
|
||
// 投影到初始方向
|
||
float dot = Vector2.Dot(toNewPos, initialDirection);
|
||
newPos = keyPos + initialDirection * Mathf.Sign(dot) * toNewPos.magnitude;
|
||
}
|
||
}
|
||
|
||
rectTransform.anchoredPosition = newPos;
|
||
|
||
// 如果是关键帧点,同时移动切线点
|
||
if (IO == 0)
|
||
{
|
||
foreach (PointMover tangentPoint in subpointMover)
|
||
{
|
||
if (tangentPoint != null)
|
||
{
|
||
tangentPoint.rectTransform.anchoredPosition += mouseDelta;
|
||
}
|
||
}
|
||
}
|
||
|
||
yield return null;
|
||
}
|
||
|
||
if (windowDragger != null)
|
||
{
|
||
windowDragger.Lock = false;
|
||
}
|
||
UpdateParentCurve();
|
||
}
|
||
|
||
public void UpdateParentCurve()
|
||
{
|
||
parent.UpdateCurveFromImages();
|
||
parent.DrawCurveToRawImage();
|
||
parent.UpadteValue();
|
||
parent.CreateKeyframeImages();
|
||
}
|
||
|
||
}
|
||
} |