UniversalViewer/Assets/Scripts/ModelViewerBase/Inverse Kinematics/InverseKinematics.cs

157 lines
4.4 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InverseKinematics : MonoBehaviour {
private Material lineMaterial;
private Dictionary<GameObject, Transform[]> linePoints = new Dictionary<GameObject, Transform[]>();
public bool SoftEnabled = true;
public Transform upperArm;
public Transform forearm;
public Transform hand;
public Transform elbow;
public Transform target;
[Space(20)]
public Vector3 uppperArm_OffsetRotation;
public Vector3 forearm_OffsetRotation;
public Vector3 hand_OffsetRotation;
[Space(20)]
public bool handMatchesTargetRotation = true;
[Space(20)]
public bool linesVisible = true;
public bool forceLinesInvisible = true;
float angle;
float upperArm_Length;
float forearm_Length;
float arm_Length;
float targetDistance;
float adyacent;
public void SpawnLines(Color specialColor) {
lineMaterial = new Material(Shader.Find("Legacy Shaders/Particles/Alpha Blended Premultiply"));
NewLine(upperArm, elbow, 0.005f, Color.yellow);
NewLine(elbow, target, 0.005f, Color.yellow);
NewLine(upperArm, target, 0.005f, Color.white);
NewLine(forearm, elbow, 0.01f, specialColor);
}
void NewLine(Transform point1, Transform point2, float width, Color color)
{
GameObject go = new GameObject("line");
go.layer = 5;
go.transform.SetParent(this.transform);
var lr = go.AddComponent<LineRenderer>();
lr.startWidth = lr.endWidth = width;
lr.startColor = lr.endColor = color;
lr.sharedMaterial = lineMaterial;
linePoints.Add(go, new Transform[] { point1, point2 });
}
void UpdateLines()
{
foreach(var kv in linePoints)
{
var lr = kv.Key.GetComponent<LineRenderer>();
if (!SoftEnabled)
{
if(lr.enabled != SoftEnabled)
{
lr.enabled = SoftEnabled;
}
}
else if((lr.enabled != linesVisible) || (lr.enabled && forceLinesInvisible))
{
if(forceLinesInvisible)
{
lr.enabled = false;
}
else
{
lr.enabled = linesVisible;
}
}
for (int i = 0; i < kv.Value.Length; i++)
{
lr.SetPosition(i, kv.Value[i].position);
}
}
}
// Update is called once per frame
void LateUpdate () {
if(upperArm != null && forearm != null && hand != null && elbow != null && target != null)
{
if (SoftEnabled)
{
upperArm_Length = Vector3.Distance(upperArm.position, forearm.position);
forearm_Length = Vector3.Distance(forearm.position, hand.position);
arm_Length = upperArm_Length + forearm_Length;
targetDistance = Vector3.Distance(upperArm.position, target.position);
targetDistance = Mathf.Min(targetDistance, arm_Length - arm_Length * 0.001f);
upperArm.LookAt(target, elbow.position - upperArm.position);
upperArm.Rotate(uppperArm_OffsetRotation);
Vector3 cross = Vector3.Cross(elbow.position - upperArm.position, forearm.position - upperArm.position);
adyacent = ((upperArm_Length * upperArm_Length) - (forearm_Length * forearm_Length) + (targetDistance * targetDistance)) / (2 * targetDistance);
angle = Mathf.Acos(adyacent / upperArm_Length) * Mathf.Rad2Deg;
if (float.IsNaN(angle))
{
return;
}
Vector3 oldPosition = upperArm.localPosition;
upperArm.RotateAround(upperArm.position, cross, -angle);
upperArm.localPosition = oldPosition;
forearm.LookAt(target, cross);
forearm.Rotate(forearm_OffsetRotation);
if (handMatchesTargetRotation)
{
hand.rotation = target.rotation;
hand.Rotate(hand_OffsetRotation);
}
}
else
{
//target.position = hand.position;
//target.rotation = hand.rotation;
//target.Rotate(-hand_OffsetRotation);
//elbow.position = forearm.position;
}
UpdateLines();
}
}
private void OnDestroy()
{
Destroy(lineMaterial);
foreach(var i in linePoints)
{
Destroy(i.Key);
}
Destroy(elbow.gameObject);
Destroy(target.gameObject);
}
void OnDrawGizmos(){
if (linesVisible) {
if(upperArm != null && elbow != null && hand != null && target != null && elbow != null){
Gizmos.color = Color.gray;
Gizmos.DrawLine (upperArm.position, forearm.position);
Gizmos.DrawLine (forearm.position, hand.position);
Gizmos.color = Color.red;
Gizmos.DrawLine (upperArm.position, target.position);
Gizmos.color = Color.blue;
Gizmos.DrawLine (forearm.position, elbow.position);
}
}
}
}