AnimationCurve关键帧数值修改小工具

news/2024/11/18 23:45:30/文章来源:https://www.cnblogs.com/sailJs/p/18198922

效果图

 

用途:界面动效已经由动效人员A做完(假设k了100帧),然后UI同事又把一些节点的位置做了10px的调整

此时一帧一帧去手动改,费事费力还可能出错。

这个工具的用途就是:对相关节点的所有关键帧批量做偏移。

public class AnimClipEditWnd : EditorWindow
{[MenuItem("MyTools/AnimClipEdit", false)]static void ShowWindow(){var win = GetWindow(typeof(AnimClipEditWnd), false, "AnimClipEdit");win.minSize = new Vector2(500, 300);}private Vector2 m_ScrollPos;private AnimationClip m_Clip;private EditorCurveBinding[] m_CurveBindings;private List<string> m_PathList = new List<string>();private Dictionary<string, List<string>> m_PathPropNamesDict = new Dictionary<string, List<string>>();private int m_PathOptionIndex;private GUIContent[] m_PathOptions;private GUIContent m_LabelPath = new GUIContent("path");private int m_PropNameOptionIndex;private string[] m_PropNameOptions;private AnimationCurve m_Curve;private int m_CurveBindingIndex;private float m_Delta;private void OnGUI(){m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos);{OnGUI_ScrollView();}EditorGUILayout.EndScrollView();}private void OnGUI_ScrollView(){var clip = (AnimationClip)EditorGUILayout.ObjectField("Clip", m_Clip, typeof(AnimationClip), false);bool isClipChange = m_Clip != clip;m_Clip = clip;if (null != clip){if (GUILayout.Button($"Refresh"))isClipChange = true;}bool isPathOptionChange = false;if (isClipChange){isPathOptionChange = true;m_CurveBindings = null;m_PathList.Clear();m_PathPropNamesDict.Clear();m_PathOptionIndex = 0;m_PathOptions = null;m_PropNameOptionIndex = 0;m_PropNameOptions = null;if (null != clip){m_CurveBindings = AnimationUtility.GetCurveBindings(clip);foreach (var b in m_CurveBindings){if (!m_PathPropNamesDict.TryGetValue(b.path, out var list)){list = new List<string>();m_PathPropNamesDict.Add(b.path, list);m_PathList.Add(b.path);}if (!IsIgnoredPropty(b.propertyName)){list.Add(b.propertyName);}}m_PathOptions = new GUIContent[m_PathList.Count];for (int i = 0; i < m_PathList.Count; ++i)m_PathOptions[i] = new GUIContent(m_PathList[i].Replace("/", "\\"));}}if (null == m_Clip) return;bool isPropNameOptionChange = false;int pathOptionIndex = EditorGUILayout.Popup(m_LabelPath, m_PathOptionIndex, m_PathOptions);if (isPathOptionChange || m_PathOptionIndex != pathOptionIndex){Debug.Log($"PathOptionChange: {m_PathOptionIndex} -> {pathOptionIndex}");m_PathOptionIndex = pathOptionIndex;string path = m_PathList[pathOptionIndex];var propNameList = m_PathPropNamesDict[path];m_PropNameOptions = propNameList.ToArray();m_PropNameOptionIndex = 0;isPropNameOptionChange = true;}int propNameOptionIndex = EditorGUILayout.Popup("propName", m_PropNameOptionIndex, m_PropNameOptions);if (isPropNameOptionChange || m_PropNameOptionIndex != propNameOptionIndex){Debug.Log($"PropNameOptionChange: {m_PropNameOptionIndex} -> {propNameOptionIndex}");m_PropNameOptionIndex = propNameOptionIndex;string path = m_PathList[pathOptionIndex];string propName = m_PropNameOptions[m_PropNameOptionIndex];UpdateCurveAndBinding(m_Clip, path, propName);}if (null != m_Curve){GUILayout.Space(10);EditorGUILayout.CurveField(m_Curve, GUILayout.Height(100));Keyframe[] keyFrames = m_Curve.keys;EditorGUILayout.LabelField("所有关键帧:");EditorGUILayout.BeginVertical("box");for (int i = 0; i < keyFrames.Length; ++i){var kf = keyFrames[i];EditorGUILayout.LabelField($"{i} -> t: {kf.time}, v: {kf.value}");}EditorGUILayout.EndVertical();}GUILayout.Space(10);m_Delta = EditorGUILayout.FloatField("Delta", m_Delta);if (GUILayout.Button("所有关键帧的值+Delta")){if (null != m_Curve){Keyframe[] keyFrames = m_Curve.keys;for (int i = 0; i < keyFrames.Length; ++i){Keyframe kf = keyFrames[i];float old = kf.value;kf.value = TrimFloat(old + m_Delta);Debug.Log($"idx:{i}, t:{TrimFloat(kf.time)}, old:{old} -> {kf.value}");m_Curve.MoveKey(i, kf);}AnimationUtility.SetEditorCurve(m_Clip, m_CurveBindings[m_CurveBindingIndex], m_Curve);EditorUtility.SetDirty(m_Clip);AssetDatabase.SaveAssets();//AssetDatabase.Refresh();Debug.Log($"finish");}}}public static float TrimFloat(float f){int i = (int)(f * 1000);float result = i / 1000.0f;return result;}private void UpdateCurveAndBinding(AnimationClip clip, string path, string propName){m_Curve = null;int index = 0;foreach (var b in m_CurveBindings){if (b.path == path){//Debug.Log($"path:{b.path}, propName:{b.propertyName}, type:{b.type.Name}, discrete:{b.isDiscreteCurve}, pptr:{b.isPPtrCurve}");if (b.propertyName == propName){m_Curve = AnimationUtility.GetEditorCurve(clip, b);m_CurveBindingIndex = index;break;}}index++;}}private bool IsIgnoredPropty(string propertyName){switch (propertyName){case "m_Maskable":case "m_IsActive":case "m_RaycastTarget":case "m_FillCenter":case "m_FillMethod":case "m_PixelsPerUnitMultiplier":case "m_PreserveAspect"://bool类型忽略return true;}return false;}}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/708024.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

elastic使用postman操作

1、账号认证 2、elastic索引put请求,创建索引 get请求,查询所有索引get请求,查询索引 delete请求,删除索引 put请求,增加文档数据 get请求,查询文档数据简单查询,按id简单查询,查询固定index索引下的所有数据 修改数据整条修改局部修改

Python没有服务器如何部署运行Shiny应用程序

原文链接:https://tecdat.cn/?p=36205 原文出处:拓端数据部落公众号 随着Web技术的快速发展,越来越多的数据科学家和开发人员倾向于使用Web应用程序进行数据分析和可视化。Shiny for Python作为一种流行的Web应用程序框架,为Python开发人员提供了便捷的数据展示和交互工具…

R语言CART决策树、随机森林、chaid树预测母婴电商平台用户寿命、流失可视化

全文链接:http://tecdat.cn/?p=31644 原文出处:拓端数据部落公众号 借着二胎政策的开放与家庭消费升级的东风,母婴市场迎来了生机盎然的春天,尤其是母婴电商行业,近年来发展迅猛。用户获取和流失是一对相对概念,就好比一个水池,有进口,也有出口。我们不能只关心进口的…

Python金融时间序列模型ARIMA 和GARCH 在股票市场预测应用|附代码数据

原文链接:http://tecdat.cn/?p=24407 最近我们被客户要求撰写关于金融时间序列模型的研究报告,包括一些图形和统计输出。 这篇文章讨论了自回归综合移动平均模型 (ARIMA) 和自回归条件异方差模型 (GARCH) 及其在股票市场预测中的应用 ( 点击文末“阅读原文”获取完整代码数…

R语言中绘图设置不输出绘图内容

001、正常绘图plot(1:10, cex = 2, pch = 19) 002、不输出绘图内容plot(1:10, cex = 2, pch = 19, type = "n") 。

AnimationClip获取关键帧信息

1,关键帧数据都保存在AnimationCurve上,所以首先要获取到这个public static AnimationCurve GetAnimCurve(AnimationClip clip, string path, string propName) {EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip);foreach (var b in bindings){if (…

Dism壳 (做系统的启动盘 多系统版本install.wim合成 界面化)

做系统优盘的时候不断的dism来dism去有些烦了 做了个小工具可以代替bat了... 没做异常处理 开始预览镜像把素材拖进去开始制作流程点击空动作后会出现创建的动作类型 其中合成就是把多个系统搓在一起用的 上面的索引代表的正是双击看到的那些信息的索引 输入对应索引然后空格分…

项目管理之八大绩效域------笔记(三)

18.3 开发方法和生命周期绩效域跟开发方法,项目交付节奏和生命周期相关的活动和职能.一、预期目标:①开发方法与项目可交付物相符合;②将项目交付与干系人价值紧密关联;③项目生命周期由促进交付节奏的项目阶段和产生项目交付物所需的开发方法组成。(项目周期的设计符合项目的…

CSAPP第二章

gcc指定不同的C语言版本 注意寻址和字节顺序讲的, 对象的地址都是从小地址开始算起, 而所谓大端法就是高位字节在前; 小端法则是低位字节在前 注意: 等号上的小圆点的组合表示"被定义为"的意思 反码有+0和-0, -0就是全为1的位模式, 负数的反码就是对应正数所有位取反…

R语言中判断数值是否带有小数点

001、不为整数> a <- 5.324 > floor(a) == a ## 截断后不相等, 说明带有小数点部分,即不为整数 [1] FALSE 002、是整数> b <- 324 > floor(b) == b ## 截断小数点后仍然相等,说明是整数 [1] TRUE 。

poj 3061 Subsequence

题目链接: 来自罗勇军《算法竞赛》书中的习题。 题意:给长度为 \(N\) 的数组和一个整数 \(S\),求总和不小于 \(S\) 的连续子序列的最小长度。 方法一:尺取法 主要思想为:当 \(a_1, a_2 , a_3\) 满足和 \(\geqslant S\),得到一个区间长度 \(3\), 那么去掉开头 \(a_1\),剩…

汇编语言基础及编译原理(网安)

汇编语言基础及编译原理 二进制基础 程序的编译 汇编与链接从c语言到可执行程序 源代码.c 编译 汇编代码.s 汇编 目标文件.o 链接(静态库直接拷贝,动态库运行时通过动态链接方式加载) 可执行文件(p)x86机器指令入门 栈 一种先进后出的数据结构 被用于保存函数的局部(保存…