【Unity】UnityでIK実装

してみました。

Unity5には標準でIKの機能があるんだけれども、Mecanimでキャラクターをセットアップすることが必須になっている。

なので、Unity5標準のIKを使わずに、自力でIKを実装してみた。

『サイクリック コーディネイト ディセント(CCD)法』というもので、考え方自体は判ってしまえばそれほど難しくない。

問題は、IKのターゲットなるワールド座標から、どうやって曲げたい関節を基準としたローカル座標を得るか、なんだけれども、これも便利な関数が用意されている。

chain.transform.InverseTransformPoint(ikTargetWorldPos).normalized;

これで得られる。

そして、出来た動作がこちらとなる。

説明がめんどくさいのでコードを全部載せちゃおう、わはは。


using UnityEngine;
using System.Collections;

public class IkTesterScr : MonoBehaviour {

public GameObject chain2;

public Quaternion initRotChain2;

public GameObject chain1;

public Quaternion initRotChain1;

public GameObject ikJoint;

public Quaternion initRotIkJoint;

public GameObject ikTarget;

public TextMesh text;

void Start() {
initRotChain2 = chain2.transform.rotation;
initRotChain1 = chain1.transform.rotation;
initRotIkJoint = ikJoint.transform.rotation;
}

void Update () {

if (ikTarget.transform.hasChanged) {

//姿勢をリセット
chain2.transform.rotation = initRotChain2;
chain1.transform.rotation = initRotChain1;
ikJoint.transform.rotation = initRotIkJoint;

for (int index = 0; index < 4; ++index) { RotateForTarget(chain1.transform, ikJoint.transform, ikTarget.transform); RotateForTarget(chain2.transform, ikJoint.transform, ikTarget.transform); } } ikTarget.transform.hasChanged = false; } public void RotateForTarget(Transform chain, Transform ikJoint, Transform ikTarget) { text.text = ""; //IKチェインからIKジョイントへのベクトル Vector3 toIkJoint = ikJoint.position; Log("ikJoint world position:" + toIkJoint); toIkJoint = chain.InverseTransformPoint(toIkJoint).normalized; Log("chain to ikJoint(local):" + toIkJoint); //IKチェインからIKターゲットへのベクトル Vector3 toIkTarget = ikTarget.position; Log("ikTarget world pos:" + toIkTarget); toIkTarget = chain.InverseTransformPoint(toIkTarget).normalized; Log("chain to ikTarget(local):" + toIkTarget); //回転軸 Vector3 axis = Vector3.Cross(toIkJoint, toIkTarget).normalized; Log("axis:" + axis); //回転量 float amount = Vector3.Dot(toIkJoint, toIkTarget); Log("amount:" + amount); //回転量をラジアンに変換 float acos = Mathf.Acos(amount); Log("acos:" + acos); //ラジアンを角度に変換 float degree = acos * Mathf.Rad2Deg; Log("degree:" + degree); chain.Rotate(axis, degree); } void Log(string log) { text.text += log + "\r\n"; } } [/csharp]

3年前

コメントを残す

メールアドレスが公開されることはありません。