Unity里的Procedural Animation agile Posted on Oct 2 2021 优秀博文 > 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [zhuanlan.zhihu.com](https://zhuanlan.zhihu.com/p/135877690) 前两天在推特上看到了个 60 秒做 ProceduralAnimation 的一个视频感觉好好玩就下来复刻了一下。原文链接 [https://twitter.com/CodeerStudio/status/1244995268065538048?s=20](https://twitter.com/CodeerStudio/status/1244995268065538048?s=20) 不能翻墙的可以看这个 B 站小伙伴的转发 [【独游工具箱】60 秒学会制作 Unity 程序化动画_哔哩哔哩 (゜ - ゜) つロ 干杯~-bilibili](https://www.bilibili.com/video/BV1Zc41187L2) 下面我来一步步分享下制作过程,因为原文只有 60 秒思路的过程我这里就详细的把每一步实现下。因为是 ik 做的所以一直没试过 Unity 那个 Animation Rigging,现在我们用那个来试这制作下吧。 首先我们从 PackageManager 里下载安装 AnimationRigging,我这里用的版本是 0.26。首先先创建个空的物命名为 LEG,然后再在 LEG 下创建空物体关节叫 Joint 最后在创建个 Cube 其 size 为 (0.1,0.1,1) Bone 当作骨头结构如下. ![](https://pic3.zhimg.com/80/v2-82d0c7e51d68d94726822caf8eff2732_1440w.jpg)![](https://pic3.zhimg.com/v2-09d4f5c7516075505960e55dfa0eaeee_r.jpg) 做完了一根骨头加关节后我们需要复制两个拼在一起,就像这样把新增的 Joint 连同 Bone 一起添加到上一个 Joint 下面即可 ![](https://pic3.zhimg.com/80/v2-d05cc37575e6b9ff1f9c82809082af52_1440w.jpg)![](https://pic1.zhimg.com/v2-10d6de03818584deb004d73d779d1d74_r.jpg) 好了基础的肢体出来后我们现在需要添加点脚本用来让他可以动起来,在 LEG 下在创建个 3 个子物体名字分别叫 Hits,Targets 和 Rig 的空物体,现在 rig 上添加个 Rig 权重我们设置为 1 ![](https://pic3.zhimg.com/v2-d844653ea7f6dea6e9f255edeb3d7502_r.jpg) 然后在 Rig 下添加个空物体然后挂载上 TwoBoneIKConstraint 组件就像这样 ![](https://pic2.zhimg.com/v2-aa934d0f89da1285ddfb4464adebc415_r.jpg) 然后在 LEG 上添加 RigBuilder 脚本并把 rig 拖动赋值过去 ![](https://pic3.zhimg.com/v2-25f5e8305a7f179846310e26f10e594e_r.jpg) 到这里 ik 基本好了一大半了,大可运行康康如果 hits 和 Targets 没有设置好位置是这样的 ![](https://pic3.zhimg.com/v2-285712472498b3ef07530856f9dcddb6_r.jpg) 可以来设置下 Hits 和 Target 的位置,这里先设置 Target 的位置 ![](https://pic2.zhimg.com/v2-e171ac43b34be0982fcf9880697764dd_b.jpg)![](https://pic3.zhimg.com/v2-9acc7cbf7cff9e4e45dd28eff403c796_r.jpg) 然后在设置 Hits 的位置到 Target 的正上方 1 米处 ![](https://pic3.zhimg.com/v2-a9a41e23c00bf8e8267ed05995b74c4e_b.jpg) 到目前为止我们的小胳膊算是能动了一半,现在我们通过脚本来控制吧。 就跟视频一样我们通过 HIts 往下发射射线的方式来控制其移动,当我们的 Target 位置和 Hits 位置大于某个值的时候我们让 Traget 的值往前进,并且如果射线射到的地方比较高则 Target 需要加上 y 轴的差值,这样就可以坡度的移动了。 ![](https://pic1.zhimg.com/v2-e599eee6581194943ecee274d93c74d8_b.jpg)![](https://pic3.zhimg.com/v2-8656b849506279441cba4d752de2386e_b.jpg) ``` Vector3 direction = desiredPosition - ikHitPOS.position; RaycastHit hit; if (Physics.SphereCast(ikHitPOS.position, Radius, direction, out hit, direction.magnitude * 2f, Layer)) { worldTarget = hit.point + new Vector3(0, OffsetPlaneDistance, 0); } else { worldTarget = restingPosition + new Vector3(0, OffsetPlaneDistance, 0); } ``` 这一步完成后基本就大功搞成了一大半了,剩下的无非就是加几条腿然后在控制下这几条腿 这里再更新个小玩具,看到那个推主还有个小飞板的 60s 教程我也跟着复刻了一下 [https://twitter.com/CodeerStudio/status/1246221868174135297?s=20](https://twitter.com/CodeerStudio/status/1246221868174135297?s=20) ![](https://pic1.zhimg.com/v2-cde9102a01f872d81093878eb3d69df8_b.jpg)![](https://pic2.zhimg.com/v2-7cc469afd1cec89551ac37870fa40b1d_b.jpg) ``` void Update() { for (int i = 0; i < vertex.Length; i++) { RaycastHit hit; Ray ray = new Ray(vertex[i].transform.position, Vector3.down); if (Physics.Raycast(ray, out hit)) { if (hit.transform.name == "Plane") { debugPos[i] = hit.point; float distance = Vector3.Distance(hit.point, vertex[i].transform.position); distance = Mathf.Clamp(1-distance, 0, 1); rg.AddForceAtPosition(Vector3.up * Mathf.Lerp(0, force, distance), vertex[i].transform.position); } } } ctrl(); } ``` 感觉推主的这两个教程做的真的是十分的棒不直接给出代码确实有种让人想着继续做下去的冲动 23333,这里也是希望大家尝试下因为这里感觉最难的不是代码那部分所以我把一开始自己折腾错的地方发出来分享下,所以在知乎我也不贴全代码啦,但是代码我直接传 Gayhub 上了有需求的小伙伴可以自行下载哦。 [https://github.com/MashiroShina/ProceduralAnimation_Demo](https://github.com/MashiroShina/ProceduralAnimation_Demo) A-Star(A*)寻路算法原理与实现 Shader中使用距离函数(Distance Function)绘制二维图形