人型动画足部IK权重曲线烘焙

简介

如下图所示,Left、Right FootIK Weight两条动画曲线用于设置人物角色足部IK时获取权重值,手动编辑且动画片段较多时比较费事,可以考虑程序化烘焙这两条足部IK权重曲线。
足部IK权重曲线

实现思路

  • 创建新的编辑器窗口,在OnGUI中获取当前所选中的游戏物体,并在该物体上获取Animator动画组件。
  • 获取动画组件中的动画片段数组,遍历该数组通过滚动视图列举动画片段,添加Bake按钮用于烘培权重曲线。
private Vector2 scroll;
private void OnGUI()
{GameObject selectedGameObject = Selection.activeGameObject;if (selectedGameObject == null){EditorGUILayout.HelpBox("未选中任何游戏物体", MessageType.Warning);return;}Animator animator = selectedGameObject.GetComponent<Animator>();if (animator == null){EditorGUILayout.HelpBox("所选游戏物体不包含Animator组件", MessageType.Warning);return;}AnimationClip[] clips = animator.runtimeAnimatorController.animationClips;if (clips.Length == 0){EditorGUILayout.HelpBox("Animator组件中的动画片段数量为零", MessageType.Warning);return;}scroll = GUILayout.BeginScrollView(scroll);for (int i = 0; i < clips.Length; i++){AnimationClip clip = clips[i];GUILayout.BeginHorizontal();GUILayout.Label(clip.name);GUILayout.FlexibleSpace();if (GUILayout.Button("Bake", GUILayout.Width(50f)))EditorCoroutineUtility.StartCoroutine(BakeCoroutine(selectedGameObject, animator, clip), this);GUILayout.EndHorizontal();}GUILayout.EndScrollView();
}

Humanoid FootIK AnimCurve Baker

  • 根据动画片段获取其资产路径、资产导入器以及对应的ModelImporterClipAnimation,如果已经有目标曲线则进行过滤,以便重新生成。
//获取资产路径
string assetPath = AssetDatabase.GetAssetPath(clip);
//获取资产导入器
ModelImporter importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
ModelImporterClipAnimation[] clipAnimations = importer.clipAnimations;
ModelImporterClipAnimation target = clipAnimations.FirstOrDefault(m => m.name == clip.name);
//过滤(如果已经有对应的两条曲线)
target.curves = target.curves.Where(m=> m.name != "Left FootIK Weight"&& m.name != "Right FootIK Weight").ToArray();
//保存、重新导入
importer.SaveAndReimport();
  • 通过AnimationClip.SampleAnimation函数进行采样,帧数 = 动画时长 * 采样率。采样时根据脚是否处于地面记录当前帧的值,在地面时权重为1,不在地面时权重为0。注意采样前记录初始姿态,采样后进行恢复。
//采样率30
int samplingRate = 30;
int frames = Mathf.CeilToInt(clip.length * samplingRate);
Keyframe[] leftFootKeyFrames = new Keyframe[frames];
Keyframe[] rightFootKeyFrames = new Keyframe[frames];
//采样前记录初始姿态
Dictionary<Transform, (Vector3, Quaternion)> pose = new Dictionary<Transform, (Vector3, Quaternion)>();
Transform[] children = animator.GetComponentsInChildren<Transform>();
for (int i = 0; i < children.Length; i++)
{Transform child = children[i];pose.Add(child, (child.position, child.rotation));
}
//采样
for (int i = 0; i < frames; i++)
{clip.SampleAnimation(go, (float)i / samplingRate);bool isFootGroundedLeft = IsFootGrounded(animator, HumanBodyBones.LeftFoot);bool isFootGroundedRight = IsFootGrounded(animator, HumanBodyBones.RightFoot);//在地面时权重为1 不在地面时权重为0leftFootKeyFrames[i] = new Keyframe((float)i / frames, isFootGroundedLeft ? 1f : 0f);rightFootKeyFrames[i] = new Keyframe((float)i / frames, isFootGroundedRight ? 1f : 0f);yield return null;
}
//采样后恢复初始姿态
foreach (var kv in pose)
{kv.Key.position = kv.Value.Item1;kv.Key.rotation = kv.Value.Item2;
}
  • 进行过滤,当帧值与前帧、后帧值都一样的帧是不需要的。
//过滤(当帧值与前帧、后帧值都一样)
leftFootKeyFrames = Enumerable.Range(0, frames).Where(i =>{bool sameWithPrev = (i - 1) >= 0 && leftFootKeyFrames[i - 1].value == leftFootKeyFrames[i].value;bool sameWithLast = (i + 1) < frames && leftFootKeyFrames[i + 1].value == leftFootKeyFrames[i].value;return !sameWithPrev || !sameWithLast;}).Select(i => leftFootKeyFrames[i]).ToArray();
rightFootKeyFrames = Enumerable.Range(0, frames).Where(i =>{bool sameWithPrev = (i - 1) >= 0 && rightFootKeyFrames[i - 1].value == rightFootKeyFrames[i].value;bool sameWithLast = (i + 1) < frames && rightFootKeyFrames[i + 1].value == rightFootKeyFrames[i].value;return !sameWithPrev || !sameWithLast;}).Select(i => rightFootKeyFrames[i]).ToArray();
  • 添加新生成的两条动画曲线。
ClipAnimationInfoCurve leftAnimInfoCurve = new ClipAnimationInfoCurve()
{name = "Left FootIK Weight",curve = new AnimationCurve(leftFootKeyFrames)
};
ClipAnimationInfoCurve rightAnimInfoCurve = new ClipAnimationInfoCurve()
{name = "Right FootIK Weight",curve = new AnimationCurve(rightFootKeyFrames)
};
//添加生成的两条曲线
target.curves = target.curves.Concat(new ClipAnimationInfoCurve[2] { leftAnimInfoCurve, rightAnimInfoCurve }).ToArray();
importer.clipAnimations = clipAnimations;
importer.SaveAndReimport();

相关工具

生成过程使用了协程,在Runtime运行时可以通过MonoBehaviour中的StartCoroutine开启协程,而工具工作在编辑器环境。可以使用Package Manager中的协程工具Editor Coroutines,如下图所示。

Editor Coroutines

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

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

相关文章

FART12刷机脱壳记录笔记

其他脱壳笔记&#xff1a; https://codeooo.blog.csdn.net/article/details/126891503 fart12 脱壳系统 可以脱邦邦 爱加密 企业壳 等&#xff1b; 寒冰大佬的脱壳王 本文记录下刷机过程&#xff0c;方便以后查看使用。 adb授权和ome锁要开着 代表锁是开着状态 如果出现&a…

关于标准库中的反向迭代器

什么是迭代器&#xff1f; 迭代器&#xff08;iterator&#xff09;有时又称光标&#xff08;cursor&#xff09;是程序设计的软件设计模式&#xff0c;可在容器对象&#xff08;container&#xff0c;例如list或vector&#xff09;上遍历访问的接口&#xff0c;通常来…

Ps:图框工具

图框工具 Frame Tool是自 Ps 2019 版开始新增的一个工具。 图框 Frame可用于限制图像的显示范围&#xff0c;在设计过程中&#xff0c;还常常可起到占位符的功能。 快捷键&#xff1a;K 使用图框工具&#xff0c;对于快速相册排版、创建某种形式的特效等有一定的帮助。比起使用…

ctfshow 杂项签到

ctfshow的杂项签到题&#xff0c;下载压缩包之后里面有图片。 直接将图片用010editor打开&#xff0c;检索ctfshow可以看到答案。

Frequency-domain MLPs are More EffectiveLearners in Time Series Forecasting

本论文来自于 37th Conference on Neural Information Processing Systems (NeurIPS 2023) Abstract 时间序列预测在金融、交通、能源、医疗等不同行业中发挥着关键作用。虽然现有文献设计了许多基于 RNN、GNN 或 Transformer 的复杂架构&#xff08;注意力机制的计算太占用资…

.net6使用Sejil可视化日志

&#xff08;关注博主后&#xff0c;在“粉丝专栏”&#xff0c;可免费阅读此文&#xff09; 之前介绍了这篇.net 5使用LogDashboard_.net 5logdashboard rootpath-CSDN博客 这篇文章将会更加的简单&#xff0c;最终的效果都是可视化日志。 在程序非常庞大的时候&…

blender scripting 编写

blender scripting 编写 一、查看ui按钮对应的代码二、查看或修改对象名称三、案例&#xff1a;渲染多张图片并导出对应的相机参数 一、查看ui按钮对应的代码 二、查看或修改对象名称 三、案例&#xff1a;渲染多张图片并导出对应的相机参数 注&#xff1a;通过ui交互都设置好…

GEE数据集——USGS全球地震数据集

美国地质勘探局全球地震数据集 美国地质调查局地震灾害计划 (EHP) 提供全面的地震数据集&#xff0c;为全球监测、研究和地震防备提供宝贵资源。该数据集包含来自各种来源的地震信息&#xff0c;包括地震台、卫星图像和地面观测。持续更新&#xff0c;截至 2023 年 10 月 10 日…

跨境电商新纪元:无人驾驶技术如何颠覆物流未来

在全球化蓬勃发展的今天&#xff0c;跨境电商作为商业模式的一种新范式&#xff0c;正以前所未有的速度崛起。与此同时&#xff0c;无人驾驶技术作为物流领域的创新力量&#xff0c;正在为跨境电商带来翻天覆地的变革。本文将深入研究跨境电商新纪元下&#xff0c;无人驾驶技术…

Linux之文件目录

pwd 显示当前工作目录的绝对路径 ls显示目录中的内容 语法&#xff1a;ls [选项] 目录或文件常用选项&#xff1a; -a : 显示当前目录的所有文件和目录&#xff0c;包括隐藏的-l : 以列表的方式显示信息 cd切换目录 语法&#xff1a;cd [参数] &#xff08;切换到指定路径&…

Odoo16 实用功能之在Form视图控制字段的显示以及禁止编辑和禁止创建

目录 1、控制字段的显示 2、禁止编辑和禁止创建 1、控制字段的显示 在第一个字段没有选择的时候&#xff0c;让第二个字段不显示&#xff0c;选择之后第二个字段才显示&#xff0c;这个如何实现的&#xff1f; 以下是一个示例&#xff0c;假设disk_type是一个Selection字段&am…

数据通信网络基础华为ICT网络赛道

目录 前言&#xff1a; 1.网络与通信 2.网络类型与网络拓扑 3.网络工程与网络工程师 前言&#xff1a; 数据通信网络基础是通信领域的基本概念&#xff0c;涉及数据传输、路由交换、网络安全等方面的知识。华为ICT网络赛道则是华为公司提出的一种技术路径&#xff0c;旨在通…

python爬虫进阶篇:Scrapy中使用Selenium+Firefox浏览器爬取国债逆回购并发送QQ邮件通知

一、前言 每到年底国债逆回购的利息都会来一波高涨&#xff0c;利息会比银行的T0的理财产品的利息高&#xff0c;所以可以考虑写个脚本每天定时启动爬取逆回购数据&#xff0c;实时查看利息&#xff0c;然后在利息高位及时去下单。 二、环境搭建 详情请看《python爬虫进阶篇…

AI数字人克隆系统OEM:为未来创造更多可能

随着科技的发展&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域取得了重要突破。其中&#xff0c;一个备受关注的领域是AI数字人克隆系统。作为一种创新的技术&#xff0c;它引发了人们的浓厚兴趣。本文将以探秘AI数字人克隆系统OEM源码为主题&#xff0c;深入了解这…

如何从0到1搭建一个SpringBoot项目

SpringBoot是大家使用最多的一个Java框架了&#xff0c;今日就来详细介绍一下如何去创建一个SpringBoot项目 一、准备工作 首先要来看你的IDEA版本&#xff0c;如果你的IDEA是【专业版】的&#xff0c;那么你就无需安装任何的插件&#xff0c;直接就可以创建SpringBoot的项目了…

【MIMO 从入门到精通】[P4]【MIMO Communications】

前言&#xff1a; Explains the main approaches to multi-input multi-output (MIMO) communications, including Beamforming, Zero Forcing, and MMSE. * Note that at the 9:19min mark, I made a slight "voice typo", where I should have said: "you nee…

世界首款配备M.2固态硬盘的树莓派Pi 5工业计算机发布!

多年来&#xff0c;上海晶珩一直秉承创新理念&#xff0c;持续不断地推陈出新。在成功推出一系列基于树莓派 Raspberry Pi CM4 的工业计算机后&#xff0c;现推出了全球首款搭载 M.2 固态硬盘的 Raspberry Pi 5 工业计算机ED-IPC3020系列。 ED-IPC3020搭载强大的Broadcom BCM27…

交换机vlan划分方法,学会这三招就够!

你们好&#xff0c;我的网工朋友。 交换机的配置我们说过很多&#xff0c;总有一些朋友会提到vlan的划分&#xff0c;今天就给你说下具体的应用。 关于vlan的划分方法有很多&#xff0c;项目应用中较多的方法就是基于端口划分vlan、基于mac地址划分vlan、基于ip地址划分vlan……

Redis相关的那些事(一)

背景 目前工作所负责的工作主要是投放业务&#xff0c;属于读高并发场景&#xff0c;记录一下之前碰到的redis相关的问题。 热点大值Key&缓存击穿问题 问题表现 在某次流量峰值过程中&#xff0c;redis的CPU突然飙升&#xff0c;从监控看起来就是CPU飙升到一定程度&…

如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问

作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; 前言…