Skip to content

Commit

Permalink
1.Make the code compilable. 2.Improve arm IK
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesBear committed Jun 22, 2017
1 parent 6f63731 commit e1f76d4
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 67 deletions.
185 changes: 185 additions & 0 deletions Assets/Scripts/ThreePointIK.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using UnityEngine;
using System.Collections;

public class ThreePointIK : MonoBehaviour {

public Transform IKBone1;
public Transform IKBone2;
public Transform IKBone3;
public Transform target;

// whether UpdateIK() is called by Update() or called externally
public bool manualUpdateIK = false;
public BendNormalStrategy bendNormalStrategy = BendNormalStrategy.followTarget;
//public float debugAngle = 0f;
public Vector3 defaultBendNormal;

public enum BendNormalStrategy
{
followTarget,
rightArm,
leftArm,
head,
//rightFoot,
//leftFoot,
}

/// <summary>
/// Gets the rotation that can be used to convert a rotation from one axis space to another.
/// </summary>
public static Quaternion RotationToLocalSpace(Quaternion space, Quaternion rotation)
{
return Quaternion.Inverse(Quaternion.Inverse(space) * rotation);
}

///// <summary>
///// Gets the Quaternion from rotation "from" to rotation "to".
///// </summary>
//public static Quaternion FromToRotation(Quaternion from, Quaternion to)
//{
// if (to == from) return Quaternion.identity;

// return to * Quaternion.Inverse(from);
//}

public class Bone
{

public float length;
public Transform trans;
private Quaternion targetToLocalSpace;
private Vector3 defaultLocalBendNormal;

public void Initiate(Vector3 childPosition, Vector3 bendNormal) {
// Get default target rotation that looks at child position with bendNormal as up
Quaternion defaultTargetRotation = Quaternion.LookRotation(childPosition - trans.position, bendNormal);

// Covert default target rotation to local space
targetToLocalSpace = RotationToLocalSpace(trans.rotation, defaultTargetRotation);

defaultLocalBendNormal = Quaternion.Inverse(trans.rotation) * bendNormal;
}


public Quaternion GetRotation(Vector3 direction, Vector3 bendNormal) {
return Quaternion.LookRotation(direction, bendNormal) * targetToLocalSpace;
}

public Vector3 GetBendNormalFromCurrentRotation() {
return trans.rotation * defaultLocalBendNormal;
}

public Vector3 GetBendNormalFromCurrentRotation(Vector3 defaultNormal) {
return trans.rotation * defaultNormal;
}
}

private Bone bone1;
private Bone bone2;
private Bone bone3;

private bool initialized = false;

// Use this for initialization
void Start () {
Init ();
}

// Update is called once per frame
void Update () {
if (!initialized) {
return;
}

if (!manualUpdateIK) {
UpdateIK ();
}
}

Vector3 GetBendDirection(Vector3 IKPosition, Vector3 bendNormal) {
Vector3 direction = IKPosition - bone1.trans.position;
if (direction == Vector3.zero) return Vector3.zero;

float directionSqrMag = direction.sqrMagnitude;
float directionMagnitude = (float)Mathf.Sqrt(directionSqrMag);

float x = (directionSqrMag + bone1.length*bone1.length - bone2.length*bone2.length) / 2f / directionMagnitude;
float y = (float)Mathf.Sqrt(Mathf.Clamp(bone1.length*bone1.length - x * x, 0, Mathf.Infinity));

Vector3 yDirection = Vector3.Cross(direction, bendNormal);
return Quaternion.LookRotation(direction, yDirection) * new Vector3(0f, y, x);
}

public void UpdateIK()
{
//clamp target if distance to target is longer than bones combined
Vector3 actualTargetPos;
float overallLength = Vector3.Distance (bone1.trans.position, target.position);
if (overallLength > bone1.length + bone2.length) {
actualTargetPos = bone1.trans.position + (target.position - bone1.trans.position).normalized * (bone1.length + bone2.length);
overallLength = bone1.length + bone2.length;
} else
actualTargetPos = target.position;

//calculate bend normal
//you may need to change this based on the model you chose
Vector3 bendNormal = Vector3.zero;
switch (bendNormalStrategy)
{
case BendNormalStrategy.followTarget:
bendNormal = - Vector3.Cross (actualTargetPos - bone1.trans.position, target.forward);
break;
case BendNormalStrategy.rightArm:
bendNormal = Vector3.down;
break;
case BendNormalStrategy.leftArm:
bendNormal = Vector3.up;
break;
case BendNormalStrategy.head:
bendNormal = bone1.GetBendNormalFromCurrentRotation();
break;
//case BendNormalStrategy.rightFoot:
// bendNormal = -Vector3.Cross(actualTargetPos - bone1.trans.position, target.forward);
// break;
//case BendNormalStrategy.leftFoot:
// bendNormal = -Vector3.Cross(actualTargetPos - bone1.trans.position, target.forward);
// break;
default:
Debug.LogError ("Undefined bendnormal strategy: " + bendNormalStrategy);
break;
}

//calculate bone1, bone2 rotation
Vector3 bendDirection = GetBendDirection(actualTargetPos, bendNormal);

// Rotating bone1
bone1.trans.rotation = bone1.GetRotation(bendDirection, bendNormal);

// Rotating bone 2
bone2.trans.rotation = bone2.GetRotation(actualTargetPos - bone2.trans.position, bone2.GetBendNormalFromCurrentRotation(defaultBendNormal));
//bone2.trans.rotation = bone2.GetRotation(actualTargetPos - bone2.trans.position, Quaternion.AngleAxis(debugAngle, target.forward)* target.up);

bone3.trans.rotation = target.rotation;
}

void Init()
{
if (IKBone1 == null || IKBone2 == null || IKBone3 == null || target == null) {
Debug.LogError ("bone or target empty, IK aborted");
return;
}

bone1 = new Bone{ trans = IKBone1 };
bone2 = new Bone{ trans = IKBone2 };
bone3 = new Bone{ trans = IKBone3 };
bone1.length = Vector3.Distance (bone1.trans.position, bone2.trans.position);
bone2.length = Vector3.Distance (bone2.trans.position, bone3.trans.position);

Vector3 bendNormal = defaultBendNormal;
//if (bendNormal == Vector3.zero) bendNormal = Vector3.forward;
bone1.Initiate(bone2.trans.position, bendNormal);
bone2.Initiate(bone3.trans.position, bendNormal);

initialized = true;
}
}
12 changes: 12 additions & 0 deletions Assets/Scripts/ThreePointIK.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 11 additions & 62 deletions Assets/Scripts/ViveIKDemo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using RootMotion.FinalIK;

/// <summary>
/// A tracker is 'bound' to one foot, then its pose(position and rotation) can be
Expand Down Expand Up @@ -44,7 +43,7 @@ enum Stage
Transform leftHandTarget = null;
Transform rightHandTarget = null;
AnimationBlendTest animationBlender;
List<LimbIK> ikList = new List<LimbIK>(); // to fully control the execution orders of the IK solvers
List<ThreePointIK> ikList = new List<ThreePointIK>();// to fully control the execution order of the IK solvers


// Use this for initialization
Expand Down Expand Up @@ -171,83 +170,33 @@ void AdjustToHeight(float customHeight)

void StartIK()
{
var ikComps = GetComponents<RootMotion.FinalIK.LimbIK>();

// foreach (var item in ikComps)
// {
//var limbik = item as RootMotion.FinalIK.LimbIK;
//limbik.solver.bendNormal = new Vector3 (1, 0, 0);
//string targetName = limbik.solver.target.name;
//if (targetName.StartsWith("Controller"))
//{
// if (targetName.Contains ("left")) {
// limbik.solver.target = leftHandTarget;
// } else {
// limbik.solver.target = rightHandTarget;
// }
// if (limbik.solver.target != null)
// item.enabled = true;
//}
//else
//{
// item.enabled = true;
//}
// }

int headIndex = -1;


foreach (var item in ikComps)
{
var limbik = item as RootMotion.FinalIK.LimbIK;
limbik.solver.bendNormal = new Vector3(1, 0, 0);
string targetName = limbik.solver.target.name;
if (targetName.StartsWith("Controller"))
{
if (targetName.Contains("left"))
{
limbik.solver.target = leftHandTarget;
}
else {
limbik.solver.target = rightHandTarget;
}
if (limbik.solver.target != null)
ikList.Add(item);
}
else
{
if (item.solver.target == markerHead)
headIndex = ikList.Count;

ikList.Add(item);
}
var tpIkComps = GetComponents<ThreePointIK>();

foreach (var item in tpIkComps)
{
item.manualUpdateIK = true;
item.enabled = true;

ikList.Add(item);
}


headIndex = ikList.FindIndex(item => item.bendNormalStrategy == ThreePointIK.BendNormalStrategy.head);
if (headIndex >= 0)
{
Swap(ikList, 0, headIndex);
}
}


void UpdateIK()
{
var ikComps = GetComponents<RootMotion.FinalIK.LimbIK>();
foreach (var item in ikComps)
{
var limbik = item as RootMotion.FinalIK.LimbIK;
if (limbik.solver.goal == AvatarIKGoal.LeftFoot || limbik.solver.goal == AvatarIKGoal.RightFoot)
limbik.solver.bendNormal = new Vector3(1, 0, 0);
//else if (limbik.solver.goal == AvatarIKGoal.LeftHand)
// limbik.solver.bendNormal = new Vector3 (0, 0, -1);
//else if (limbik.solver.goal == AvatarIKGoal.RightHand)
// limbik.solver.bendNormal = new Vector3 (0, 0, 1);
}

foreach (var item in ikList)
{
item.UpdateSolverExternal();
item.UpdateIK();
}
}

Expand Down
Binary file modified Assets/vive_ik_demo.unity
Binary file not shown.
Binary file modified ProjectSettings/ProjectSettings.asset
Binary file not shown.
19 changes: 14 additions & 5 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ To get the full documentation:
To download the executable:
- Download "vive_ik_test.rar"

Note that the given source code is only for your reference and can't compile without error in Unity. To open this project in Unity:
- Either buy an IK plugin (for example, FinalIK) at assetstore or implement one yourself.
To run in Unity and modify the source code:
- Download this project and open the folder with Unity 5.4 (mine is 5.4.2f2).
- Double click the scene vive_ik_demo and hit "Play" button.

Special thanks to:
- RootMotion for their FinalIK. This project took inspiration from it. If you want to use professional multi-joint IK (or any kind of IK) in your game, go check out FinalIK in Unity AssetStore.


Copyright: HTC Corporation
Expand All @@ -33,8 +37,13 @@ Vive IK Demo
��ô��ÿ�ִ�г���
- ����"vive_ik_test.rar"

ע�⣬����Ŀ��Դ��������ο�����������Unity��˳�����롣��Ҫ����ɹ���Ҫ��
- ��assetstore����IK���������FinalIK���������Լ�ʵ��һ��IK�����
��ô��Unity�����м��޸Ĵ��룺
- ���ر����̣�Ȼ����Unity 5.4�򿪱��ļ��У����õ���5.4.2f2��
- ˫��vive_ik_demo������Ȼ����"Play"��ť

�ر��л��
- RootMotion�������̽�������ǵ�FinalIK�������������Ϸ����϶����IK��ȥAssetStore������FinalIK�ɡ�


Copyright: HTC Corporation
Copyright: HTC Corporation
Contact: [email protected]
Binary file modified vive_ik_test.rar
Binary file not shown.

0 comments on commit e1f76d4

Please sign in to comment.