关于UnityIK控制头部朝向目标的一些研究
(事先声明,本人为编程菜鸡,所使用的方法可能非常笨,不具备任何参考价值,请谅解)
虽然研究动画系统一段时间了,但IK也是最近这段时间才刚刚接触到的,其他部位IK暂时不提,今天我要研究的IK是头部朝向的IK。
让我们开始吧
首先,基本的基本,打开人物的Animaotr面板,添加一层IK层
接着为你的人物设置IK事件属性就好了
这里用到了两个API,分别是SetLookAtWeight和SetLookAtPosition
SetLookAtWeight的作用是设置权重,权重越低,IK所对动画造成的影响越低
SetLookAtPosition的作用是设置IK的朝向位置
主要实现思路有两种:
1、当有目标进入玩家视线时,权重缓慢增长到正常值,当目标离开时,权重又慢慢的回落到0(既IK不对动画产生任何影响)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class IKLookAT : MonoBehaviour
{
private Animator animator;
private GameObject minDictObj;
private List<GameObject> list_LookObj;
private Vector3 TempPos;
private float IkanimationSpeed = 0.8f;
private float all;
private float body;
private float head;
private float eye;
public List<GameObject> List_LookObj { get { return list_LookObj; } set { list_LookObj = value; } }
void Awake()
{
list_LookObj = new List<GameObject>();
animator = gameObject.GetComponent<Animator>();
}
private void OnAnimatorIK(int layerIndex)
{
if (list_LookObj.Count > 0)
{
float mindict = 100;
for (int i = 0; i < list_LookObj.Count; i++)
{
float dict = Vector3.Distance(transform.position, list_LookObj[i].transform.position);
if (dict < mindict) { mindict = dict; minDictObj = list_LookObj[i]; }
}
}
else { minDictObj = null; }
if (minDictObj != null)
{
LockTure();
TempPos = Vector3.Lerp(TempPos, minDictObj.transform.position, 1.5f * Time.deltaTime);
animator.SetLookAtPosition(TempPos);
}
else
{
LockFalse();
animator.SetLookAtPosition(TempPos);
}
animator.SetLookAtWeight(all, body, head, eye, IkanimationSpeed);
}
private void LockTure()
{
DOTween.To(() => all, X => all = X, 1, 5.0f);
DOTween.To(() => body, X => body = X, 0, 5.0f);
DOTween.To(() => head, X => head = X, 0.5f, 5.0f);
DOTween.To(() => eye, X => eye = X, 0.3f, 5.0f);
}
private void LockFalse()
{
DOTween.To(() => all, X => all = X, 0, 5.0f);
DOTween.To(() => body, X => body = X, 0, 5.0f);
DOTween.To(() => head, X => head = X, 0, 5.0f);
DOTween.To(() => eye, X => eye = X, 0, 5.0f);
}
}
使用这个方法,朝向目标的IK动画切换与恢复有非常缓和的效果,但是这个方法有个致命的缺点:因为设置的IK基本是影响了全局IK属性,导致其他部位的IK也会受此影响,导致IK失效
为此,我推荐使用人型骨骼动画Mask并仅选择头部动画,并将其他IK属性置于其他层,这样就不会影响到头部的IK动画了。
2、添加一个空物体作为玩家的子级,跟随玩家移动,并一直置于玩家前方,当玩家视线内没有目标时,玩家便会看向此空物体,出现目标既转向目标
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class IKLookAT : MonoBehaviour
{
private Animator animator;
private GameObject minDictObj;
private List<GameObject> list_LookObj;
private Vector3 TempLookPos;
private Transform DefaultLookPos;
public List<GameObject> List_LookObj { get { return list_LookObj; } set { list_LookObj = value; } }
void Awake()
{
list_LookObj = new List<GameObject>();
animator = gameObject.GetComponent<Animator>();
DefaultLookPos = transform.Find("DefaultLookAtObj").GetComponent<Transform>();
}
private void OnAnimatorIK(int layerIndex)
{
if (list_LookObj.Count > 0)
{
float mindict = 100;
for (int i = 0; i < list_LookObj.Count; i++)
{
float dict = Vector3.Distance(transform.position, list_LookObj[i].transform.position);
if (dict < mindict) { mindict = dict; minDictObj = list_LookObj[i]; }
}
}
else { minDictObj = null; }
if (minDictObj != null)
{
TempLookPos = Vector3.Lerp(TempLookPos, minDictObj.transform.position, 1.5f * Time.deltaTime);
animator.SetLookAtPosition(TempLookPos);
}
else
{
TempLookPos = Vector3.Lerp(TempLookPos, DefaultLookPos.position, 5.0f * Time.deltaTime);
animator.SetLookAtPosition(TempLookPos);
}
animator.SetLookAtWeight(1.0f, 0.1f, 0.5f, 0.4f, 0.8f);
}
}
使用这个方法,动画的切换将变得不再平滑,但优点在于不会影响到其他IK属性。
主要还是本人编程水准太低的原因,如果优化一下朝向的算法,或许此方法更加适合。
来源:CSDN
作者:咸值上升
链接:https://blog.csdn.net/weixin_42323967/article/details/103464740