してみました。
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]