名古屋でアプリ・VR開発を行っています
ワクワクできるゲームをガンガン開発リリース中!

HumanoidのIKを使ってみる3

こんにちは。

SAT-BOXカピバラさんです。

今回も、前回同様、UnityHumanoidIKの機能を紹介したいと思います。

前回の記事はこちらからどうぞ。
sat-box.hatenablog.jp
sat-box.hatenablog.jp


毎度お馴染み、白い人型のモデルに登場してもらいたいと思います。


相変わらず今回も哀愁を漂わせております…ん?
何かを見てますね。
f:id:sat-box:20170612181244g:plain


一体何を見ているんでしょうか。
こ、これは!


f:id:sat-box:20170612181406g:plain

ハ、ハンバーガー…!
と、茶番は置いておいて、今回はこのハンバーガーが足元に移動してきた時に足が上に乗るように設定していきたいと思います。

まずは現状。

f:id:sat-box:20170612181911g:plain

こんな感じで、足元に物を置いても足がハンバーガーの中に埋まって、足を乗せられてないですね。

前回のソースコードを若干修正しつつ、足元のコライダーに合わせて足のポジションをセットする処理を追加して行きたいと思います。

using UnityEngine;
using System.Collections;

public class IKController : MonoBehaviour
{

	[Header("HandIK")]
	[SerializeField]
	public Transform rightHandAnchor = null;
	[SerializeField]
	public Transform leftHandAnchor = null;

	[Header("LookIK")]
	[SerializeField, Range(0.0f, 1.0f)]
	private float lookTotalWeight = 0.0f;
	[SerializeField, Range(0.0f, 1.0f)]
	private float bodyWeight = 0.0f;
	[SerializeField, Range(0.0f, 1.0f)]
	private float headWeight = 0.0f;
	[SerializeField, Range(0.0f, 1.0f)]
	private float eyeWeight = 0.0f;
	[SerializeField]
	private GameObject lookTarget;

	[Header("FootIK")]
	[SerializeField]
	private bool isFootIK;


	private Animator animator;

	void Start()
	{
		animator = GetComponent<Animator>();
	}

	void OnAnimatorIK()
	{
		//アニメーターが無いときは処理しない
		if (!animator)
			return;

		//右手を固定
		if (rightHandAnchor != null)
		{
			SetIkWeight(AvatarIKGoal.RightHand, 1.0f, 1.0f);
			SetIk(AvatarIKGoal.RightHand, rightHandAnchor.position, rightHandAnchor.rotation);
		}

		//右手を固定
		if (leftHandAnchor != null)
		{
			SetIkWeight(AvatarIKGoal.LeftHand, 1.0f, 1.0f);
			SetIk(AvatarIKGoal.LeftHand, leftHandAnchor.position, leftHandAnchor.rotation);
		}

		//ターゲットの方向を向くように
		if (lookTarget != null)
		{
			animator.SetLookAtWeight(lookTotalWeight, bodyWeight, headWeight, eyeWeight);
			animator.SetLookAtPosition(lookTarget.transform.position);
		}

		if (isFootIK)
		{
			Vector3 rightPos = animator.GetIKPosition(AvatarIKGoal.RightFoot);
			Vector3 leftPos = animator.GetIKPosition(AvatarIKGoal.LeftFoot);
			Vector3 diffR = Vector3.zero;
			Vector3 diffL = Vector3.zero;
			RaycastHit ray;

			Debug.DrawLine(rightPos, rightPos  + Vector3.down);

			if (Physics.Raycast(rightPos + Vector3.up * 0.3f, Vector3.down, out ray))
			{
				diffR = (rightPos - ray.point) - Vector3.up * 0.1f;
				SetIkWeight(AvatarIKGoal.RightFoot, 1.0f, 1.0f);
				SetIk(AvatarIKGoal.RightFoot, -diffR, Quaternion.identity, true);
			}
			if (Physics.Raycast(leftPos + Vector3.up * 0.3f, Vector3.down, out ray))
			{
				diffL = (leftPos - ray.point) - Vector3.up * 0.1f;
				SetIkWeight(AvatarIKGoal.LeftFoot, 1.0f, 1.0f);
				SetIk(AvatarIKGoal.LeftFoot, -diffL, Quaternion.identity, true);
			}

			animator.bodyPosition += Mathf.Max(diffR.y, diffL.y) * Vector3.down;
		}
	}

	//IKの重みを設定する
	void SetIkWeight(AvatarIKGoal _goal, float _posWeight, float _rotWeight)
	{
		animator.SetIKPositionWeight(_goal, Mathf.Clamp(_posWeight, 0.0f, 1.0f));
		animator.SetIKRotationWeight(_goal, Mathf.Clamp(_rotWeight, 0.0f, 1.0f));
	}

	//IKを指定して固定させる
	void SetIk(AvatarIKGoal goal, Vector3 _pos, Quaternion _rot, bool isAddIKPosition = false)
	{
		if(isAddIKPosition)
			_pos +=	animator.GetIKPosition(goal);

		animator.SetIKPosition(goal, _pos);
		animator.SetIKRotation(goal, _rot);
	}
}


こんな感じです。
ちょっと段々長くなってきましたね。。。

やっていることとしては左右の足元の少し上辺りからレイを地面に向かって飛ばして、何かコライダーに当たったらそこに足を設定する、という感じです。詳しいことはソースコードを見てください(丸投げ)

無事、ハンバーガーの上に足をのせることに成功しましたね!

f:id:sat-box:20170612182351g:plain

今回は簡単にのせるだけにしましたが、いろんな方が地面の形に合わせて足の角度を変えたりなどソースコードを公開されているので、もっと細かく設定したい人はそちらを参考にどうぞ!

gametukurikata.com

tips.hecomi.com


では(^^)/