2D Procedural Animation小试:尾巴,翅膀,触手等等
Procedural Animation的百科解释:https://en.wikipedia.org/wiki/Procedural_animation
想深入了解UE4引擎中的: control rig, Unity引擎中的:Animation Rigging
最近在学习Procedural Animation相关的只是,先从2D开始。
最好理解的程序化动画就是贪吃蛇的运动,在此基础上改造添加身体部分的运动。
先简单代码,转向目标(鼠标位置)并向目标移动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[RequireComponent(typeof(Rigidbody))]
public class Controller : MonoBehaviour
{public float _speed = 1f;private Rigidbody _rigidbody;// Start is called before the first frame updatevoid Start(){_rigidbody = GetComponent<Rigidbody>();}// Update is called once per framevoid FixedUpdate(){float multiplier = 1f;if (Input.GetKey(KeyCode.LeftShift)){multiplier = 2f;GetComponentInChildren<ProceduralAnimation>().running = true;}elseGetComponentInChildren<ProceduralAnimation>().running = false;if (_rigidbody.velocity.magnitude < _speed * multiplier){float value = Input.GetAxis("Vertical");if (value != 0)_rigidbody.AddForce(0, 0, value * Time.fixedDeltaTime * 1000f);value = Input.GetAxis("Horizontal");if (value != 0)_rigidbody.AddForce(value * Time.fixedDeltaTime * 1000f, 0f, 0f);}}
}
然后添加触角逻辑:
创建空对象Tentacle,添加LineRenderer 组件并进行设置:
创建脚本Tentacle.cs 并添加到对象上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Tentacle : MonoBehaviour
{public int Length;public LineRenderer LineRend;public Vector3[] SegmentPoses;public Transform TargetDir; // 是头部位置public float TargetDist;private Vector3[] SegmentV;public float SmoothSpeed;public float TrailSpeed;// Start is called before the first frame updatevoid Start(){LineRend.positionCount = Length;SegmentPoses = new Vector3[Length];SegmentV = new Vector3[Length];}// Update is called once per framevoid Update(){SegmentPoses[0] = TargetDir.position;for (int i = 1; i < SegmentPoses.Length; i++){SegmentPoses[i] = Vector3.SmoothDamp(SegmentPoses[i], SegmentPoses[i - 1] + TargetDir.right * TargetDist, ref SegmentV[i], SmoothSpeed + i / TrailSpeed);}LineRend.SetPositions(SegmentPoses);}
}
需要自己去了解LineRenderer组件的用法。
三条尾巴, 每个尾巴的方向z分别: 180, 135 , 225
3、 给触角添加自身摆动动作。
public float TrailSpeed;
// 摆动速度,摆动幅度, 方向
public float WiggleSpeed;
public float WiggleMagnitude;
public Transform WiggleDir;
// Start is called before the first frame update
void Start()
{
LineRend.positionCount = Length;
SegmentPoses = new Vector3[Length];
SegmentV = new Vector3[Length];
}
// Update is called once per frame
void Update()
{
WiggleDir.localRotation = Quaternion.Euler(0, 0, Mathf.Sin(Time.time * WiggleSpeed) * WiggleMagnitude);
SegmentPoses[0] = TargetDir.position;
for (int i = 1; i < SegmentPoses.Length; i++)
赋值及节点的层级变化;
但是现在有个问题触角的长度在运动或者停止的时候会变长或者变短。 这个后面解决。
比如你可以做成你想要的任何效果:
改变触角的形状,皮肤比如:
创建新的材质
替换掉 Tentacle 1 中的 LineRenderer 组件中的材质
重新play 就是新的皮肤样式了。
之前提到: 但是现在有个问题触角的长度在运动或者停止的时候会变长或者变短。
public class Tentacle : MonoBehaviour{
public int Length;
public LineRenderer LineRend;
public Vector3[] SegmentPoses;
public Transform TargetDir; // 是头部位置
public float TargetDist;
private Vector3[] SegmentV;
public float SmoothSpeed;
// 摆动速度,摆动幅度, 方向
public float WiggleSpeed;
public float WiggleMagnitude;
public Transform WiggleDir;
// Start is called before the first frame update
void Start()
{
LineRend.positionCount = Length;
SegmentPoses = new Vector3[Length];
SegmentV = new Vector3[Length];
}
// Update is called once per frame
void Update()
{
WiggleDir.localRotation = Quaternion.Euler(0, 0, Mathf.Sin(Time.time * WiggleSpeed) * WiggleMagnitude);
SegmentPoses[0] = TargetDir.position;
for (int i = 1; i < SegmentPoses.Length; i++)
{
// normalized 0~1 达到目标距离时的方向 暂停相同的
Vector3 targetPos = SegmentPoses[i - 1] + (SegmentPoses[i] - SegmentPoses[i - 1]).normalized * TargetDist;
SegmentPoses[i] = Vector3.SmoothDamp(SegmentPoses[i], targetPos, ref SegmentV[i], SmoothSpeed);
}
LineRend.SetPositions(SegmentPoses);
}
}
想让角色尾部尖上显示一个刺球:
public float WiggleMagnitude; public Transform WiggleDir;
public Transform TrailEnd;
// Start is called before the first frame update
void Start()
{
LineRend.positionCount = Length;
SegmentPoses = new Vector3[Length];
SegmentV = new Vector3[Length];
}
// Update is called once per frame
void Update()
{
WiggleDir.localRotation = Quaternion.Euler(0, 0, Mathf.Sin(Time.time * WiggleSpeed) * WiggleMagnitude);
SegmentPoses[0] = TargetDir.position;
for (int i = 1; i < SegmentPoses.Length; i++)
{
// normalized 0~1 达到目标距离时的方向 暂停相同的
Vector3 targetPos = SegmentPoses[i - 1] + (SegmentPoses[i] - SegmentPoses[i - 1]).normalized * TargetDist;
SegmentPoses[i] = Vector3.SmoothDamp(SegmentPoses[i], targetPos, ref SegmentV[i], SmoothSpeed);
}
LineRend.SetPositions(SegmentPoses);
TrailEnd.position = SegmentPoses[SegmentPoses.Length - 1];
}
效果:
还想弄更多的身体部位:
public Transform TrailEnd;
public Transform[] BodyParts;
// Start is called before the first frame update
void Start()
{
LineRend.positionCount = Length;
SegmentPoses = new Vector3[Length];
SegmentV = new Vector3[Length];
}
// Update is called once per frame
void Update()
{
WiggleDir.localRotation = Quaternion.Euler(0, 0, Mathf.Sin(Time.time * WiggleSpeed) * WiggleMagnitude);
SegmentPoses[0] = TargetDir.position;
for (int i = 1; i < Length; i++)
{
// normalized 0~1 达到目标距离时的方向 暂停相同的
Vector3 targetPos = SegmentPoses[i - 1] + (SegmentPoses[i] - SegmentPoses[i - 1]).normalized * TargetDist;
SegmentPoses[i] = Vector3.SmoothDamp(SegmentPoses[i], targetPos, ref SegmentV[i], SmoothSpeed);
BodyParts[i - 1].transform.position = SegmentPoses[i];
}
LineRend.SetPositions(SegmentPoses);
TrailEnd.position = SegmentPoses[SegmentPoses.Length - 1];
}
}
每个身体的部位位置被设置了, 跟随运动。
效果:
新增脚本: BodyRotation.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class BodyRotation : MonoBehaviour
{public float Speed;private Vector2 direction;public Transform Target;// Update is called once per framevoid Update(){direction = Target.position - transform.position;float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Speed * Time.deltaTime);}
}
将脚本挂在Body 对象上, 每个Body的target 是前一个body transform , 第一个Body的target 是 Root 节点Head 对象。 Speed 设置为: 10
一开始都是所有部位都是缩成一团的,应该一开始就是正常的状态, 初始化一下
void Start() {
LineRend.positionCount = Length;
SegmentPoses = new Vector3[Length];
SegmentV = new Vector3[Length];
ResetPos();
}
private void ResetPos()
{
SegmentPoses[0] = TargetDir.position;
for (int i = 1; i < Length; i++)
{
SegmentPoses[i] = SegmentPoses[i - 1] + TargetDir.right * TargetDist;
}
LineRend.SetPositions(SegmentPoses);
}
// Update is called once per frame
void Update()
{
WiggleDir.localRotation = Quaternion.Euler(0, 0, Mathf.Sin(Time.time * WiggleSpeed) * WiggleMagnitude);
自己各种尝试吧。
完结。
参考:
- https://forum.unity.com/threads/procedural-animation.885007/
- https://80.lv/articles/animating-beasts-using-the-procedural-way-in-unity/
- https://www.weaverdev.io/blog/bonehead-procedural-animation
- https://github.com/willymcgeejr/UnityProceduralAnimation
- pdf: Procedural Locomotion of Multi-Legged Characters in Dynamic Environments
- Inverse Kinematics Unity / Procedural Animation Unity
- COMPLETE PROCEDURAL ANIMATION IN 25 MINUTES
- Part 1. An Introduction to Procedural Animations
- Part 2.The Mathematics of Forward Kinematics
- Part 3.Implementing Forward Kinematics
- Part 4.An Introduction to Gradient Descent
- Part 5.Inverse Kinematics for Robotic Arms
- Part 6.Inverse Kinematics for Tentacles
- Unity PROCEDURAL ANIMATION tutorial (10 steps)
我试图分十步来解释程序动画。看看我的推特:https://twitter.com/CodeerDev
这个是知乎上已经有人实现的内容: https://zhuanlan.zhihu.com/p/135877690
https://link.zhihu.com/?target=https%3A//github.com/MashiroShina/ProceduralAnimation_Demo
- GDC : https://www.gdcvault.com/play/966/Dynamic-Walking-with-Semi-Procedural
2D Procedural Animation小试:尾巴,翅膀,触手等等相关推荐
- Uni2D Unity4.3 2D Skeletal Animation
http://www.cnblogs.com/zhaoqingqing/p/3602253.html 中文教程:参照 kakashi的CSDN博客 http://blog.csdn.net/kakas ...
- Unity 2D Skeletal Animation
本文记录在Unity中制作2D 骨骼动画的笔记 Unity版本:4.3 Uni2D 使用骨骼动画前,把Sprite Mesh 的Type 改为 Grid ,设置合适的骨骼数量和分配权重 1.选中创建好 ...
- Houdini Procedural Animation Techniques (cmiVFX--H11)
promote parameter -– (将属性提升到上一级去设定) 中键点击节点属性 facet节点用于计算法线 断开节点的所有连接--- 选中节点晃动 断开节点的特定连接线 --- 选中连接线右 ...
- Unity 2D教程: 滚动,场景和音效
http://www.tairan.com/archives/7074 原文地址:http://www.raywenderlich.com/71029/unity-4-3-2d-tutorial-sc ...
- 分享2D Unity游戏的动画制作经验
http://gamerboom.com/archives/76709 作者:Alex Rose Unity最近宣布推出额外的2D游戏支持,添加了Box 2D物理和一个精灵管理器. 但这里还是有些技巧 ...
- Unity制作Animation帧动画
1,把9个头像的图片放入Asset 2,点击图片,右侧,Texture Type里改成Sprite(2D and UI) Sprite Mode里改成Multiple 3,点击Sprite Edito ...
- Unity3d动画脚本 Animation Scripting(深入了解游戏引擎中的动画处理原理--旧的动画系统)
(来自:http://blog.sina.com.cn/s/blog_409cc4b00100qmgz.html) 也许这一篇文章的内容有点枯燥,但我要说的是如果你想深入的了解游戏引擎是如何处理动画片 ...
- Unity3d动画脚本 Animation Scripting
Unity3d动画脚本 Animation Scripting(深入了解游戏引擎中的动画处理原理) 也许这一篇文章的内容有点枯燥,但我要说的是如果你想深入的了解游戏引擎是如何处理动画片断或者素材并 让 ...
- unity3d Animation 动画系统
我使用unity3d的 Animation 系统 也有一段时间了 ,Animation 系统总的来说比较简单,我个人觉得比较复杂的情况就是比如我打cs的时候,拿着重型狙击,在跑步,突然发现敌人,这时候 ...
最新文章
- struct stat结构体的详解和用法
- HP1020打印机“传递给系统调用的数据区域太小” 如何处理?
- 程序员四大忌 你该如何避免呢?
- numberformatexception是什么异常_译文《最常见的10种Java异常问题》
- 渗透测试中dns log的使用
- wxPython:登录工具
- 二叉树遍历结果推二叉树_二叉树遍历(PreOrder,InOrder,PostOrder)
- react native 之setState
- 工业互联网为湖南制造装上“智脑”
- js 对象 浅拷贝 和 深拷贝
- 如何下载sonar?
- 周立功bms汽车锂电池管理系统解决方案
- java对外接口开发实例
- 收藏!示波器探头的选择与使用
- css文字覆盖线性渐变,利用css使文字渐变
- 鲁大师2021年度PC硬件报告:AMD跑分超神,华米OV入局笔记本
- Python爬虫爬取链家租房信息(python大作业)
- picjumbo - 提供大量高级感、观感极佳的图片素材下载,全都免费商用
- lsdyna材料定义(1) lsprepost
- AIX pv vg lv fs 文件系统