LoginSignup
4
4

More than 1 year has passed since last update.

数十行で書くなんちゃってIK

Posted at

概要

UnityにはFinalIKというのがありますが、1万円くらいするし、なんとなくIKっぽく動いてくれるだけで良い、という時には過剰という感じですし、何より色々な事情でFinalIKやそれに類するものが使えなかったりする時向けに、簡易的なIKっぽいものを書いてみました。

使い方

FinalIKに近い感じに使えるようにしたつもりです。
以下にそれぞれのスクリプトを付けて、操作対象の部分を割り当てます。
個別の説明は以下のとおりです。
TargetHandL/R:腕を動かす
TargetFootL/R:足を動かす
TargetHead:頭を動かす
TargetRoot:腰を動かす
TargetChest:胸部を曲げる
image.png

使用例

動機として、Transformの基礎的な実装しか持たないVCI(lua)でIKのような動きをさせたかった。というのがあります。

スクリプト

ArmIK.cs
using UnityEngine;

public class ArmIK : MonoBehaviour
{
    [SerializeField] Transform Target;
    [SerializeField] Transform Upper;
    [SerializeField] Transform Lower;
    [SerializeField] Transform Hand;
    [SerializeField] float LR; // 0:右、1:左

    float Distance;

    void Start()
    {
        Distance = Vector3.Distance(Upper.position, Hand.position);
    }

    void Update()
    {
        var position = Target.position - Upper.position;
        var rotation = Quaternion.LookRotation(position, Vector3.up);
        var offset = Quaternion.Euler(0, 90 * LR, 0);

        var distance = Vector3.Distance(Upper.position, Target.position);
        var max = Mathf.Max((Distance - distance) / Distance, 0);
        var upper = Quaternion.Euler(0, -90 * max * LR, 0);
        var lower = Quaternion.Euler(0, +90 * max * LR, 0);

        Upper.rotation = rotation * offset * upper;
        Lower.rotation = rotation * offset * lower;
        Hand.rotation = Target.rotation;
    }
}
LegIK.cs
using UnityEngine;

public class LegIK : MonoBehaviour
{
    [SerializeField] Transform Target;
    [SerializeField] Transform Upper;
    [SerializeField] Transform Lower;
    [SerializeField] Transform Foot;

    float Distance;

    void Start()
    {
        Distance = Vector3.Distance(Upper.position, Foot.position);
    }

    void Update()
    {
        var position = Target.position - Upper.position;
        var rotation = Quaternion.LookRotation(position, Vector3.forward);
        var offset = Quaternion.Euler(-90, 0, 0);

        var distance = Vector3.Distance(Upper.position, Target.position);
        var max = Mathf.Max((Distance - distance) / Distance, 0);
        var upper = Quaternion.Euler(-90 * max, 0, 0);
        var lower = Quaternion.Euler(+90 * max, 0, 0);

        Upper.rotation = rotation * offset * upper;
        Lower.rotation = rotation * offset * lower;
        Foot.rotation = Target.rotation;
    }
}
Look.cs
using UnityEngine;

public class Look : MonoBehaviour
{
    [SerializeField] Transform Target;
    [SerializeField] Transform Head;

    void Update()
    {
        var position = Target.position - Head.position;
        var rotation = Quaternion.LookRotation(position, Head.up);
        Head.rotation = rotation;
    }
}
Root .cs
using UnityEngine;

public class Root : MonoBehaviour
{
    [SerializeField] Transform Target;
    [SerializeField] Transform Model;

    void Update()
    {
        Model.position = Target.position;
        Model.rotation = Target.rotation;
    }
}
Chest.cs
using UnityEngine;

public class Chest : MonoBehaviour
{
    [SerializeField] Transform Target;
    [SerializeField] Transform Model;
    [SerializeField] Vector3 Offset;

    void Update()
    {
        Target.position = Model.position + Offset;
        Model.rotation = Target.rotation;
    }
}

補足

基本的な考え方ですが、LookAt的な動きに加えて、手足の長さに対してターゲットが近ければ肘膝を曲げる。という考え方です。頭はまさにLookAt的な動きそのままです。腰はただ移動しているだけ、胸は曲げてるだけ、になります。また、ここに書いてあるスクリプトのままだと、全体の方向が変わった時に足の向きとかおかしくなるので、ターゲットの正面を使うとかの対応が必要だと思います。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4