123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- //======= Copyright (c) Valve Corporation, All rights reserved. ===============
- using UnityEngine;
- using System.Collections;
- namespace Valve.VR.InteractionSystem.Sample
- {
- public class FloppyHand : MonoBehaviour
- {
- protected float fingerFlexAngle = 140;
- public SteamVR_Action_Single squeezyAction = SteamVR_Input.GetAction<SteamVR_Action_Single>("Squeeze");
- public SteamVR_Input_Sources inputSource;
- [System.Serializable]
- public class Finger
- {
- public float mass;
- [Range(0, 1)]
- public float pos;
- public Vector3 forwardAxis;
- public SkinnedMeshRenderer renderer;
- [HideInInspector]
- public SteamVR_Action_Single squeezyAction;
- public SteamVR_Input_Sources inputSource;
- public Transform[] bones;
- public Transform referenceBone;
- public Vector2 referenceAngles;
- public enum eulerAxis
- {
- X, Y, Z
- }
- public eulerAxis referenceAxis;
- [HideInInspector]
- public float flexAngle;
- private Vector3[] rotation;
- private Vector3[] velocity;
- private Transform[] boneTips;
- private Vector3[] oldTipPosition;
- private Vector3[] oldTipDelta;
- private Vector3[,] inertiaSmoothing;
- float squeezySmooth;
- private int inertiaSteps = 10;
- private float k = 400;
- private float damping = 8;
- private Quaternion[] startRot;
- public void ApplyForce(Vector3 worldForce)
- {
- for (int i = 0; i < startRot.Length; i++)
- {
- velocity[i] += worldForce / 50;
- }
- }
- public void Init()
- {
- startRot = new Quaternion[bones.Length];
- rotation = new Vector3[bones.Length];
- velocity = new Vector3[bones.Length];
- oldTipPosition = new Vector3[bones.Length];
- oldTipDelta = new Vector3[bones.Length];
- boneTips = new Transform[bones.Length];
- inertiaSmoothing = new Vector3[bones.Length, inertiaSteps];
- for (int i = 0; i < bones.Length; i++)
- {
- startRot[i] = bones[i].localRotation;
- if (i < bones.Length - 1)
- {
- boneTips[i] = bones[i + 1];
- }
- }
- }
- public void UpdateFinger(float deltaTime)
- {
- if (deltaTime == 0)
- return;
- float squeezeValue = 0;
- if (squeezyAction != null && squeezyAction.GetActive(inputSource))
- squeezeValue = squeezyAction.GetAxis(inputSource);
- squeezySmooth = Mathf.Lerp(squeezySmooth, Mathf.Sqrt(squeezeValue), deltaTime * 10);
- if (renderer.sharedMesh.blendShapeCount > 0)
- {
- renderer.SetBlendShapeWeight(0, squeezySmooth * 100);
- }
- float boneRot = 0;
- if (referenceAxis == eulerAxis.X)
- boneRot = referenceBone.localEulerAngles.x;
- if (referenceAxis == eulerAxis.Y)
- boneRot = referenceBone.localEulerAngles.y;
- if (referenceAxis == eulerAxis.Z)
- boneRot = referenceBone.localEulerAngles.z;
- boneRot = FixAngle(boneRot);
- pos = Mathf.InverseLerp(referenceAngles.x, referenceAngles.y, boneRot);
- if (mass > 0)
- {
- for (int boneIndex = 0; boneIndex < bones.Length; boneIndex++)
- {
- bool useOffset = boneTips[boneIndex] != null;
- if (useOffset) // inertia sim
- {
- Vector3 offset = (boneTips[boneIndex].localPosition - bones[boneIndex].InverseTransformPoint(oldTipPosition[boneIndex])) / deltaTime;
- Vector3 inertia = (offset - oldTipDelta[boneIndex]) / deltaTime;
- oldTipDelta[boneIndex] = offset;
- Vector3 drag = offset * -2;
- inertia *= -2f;
- for (int offsetIndex = inertiaSteps - 1; offsetIndex > 0; offsetIndex--) // offset inertia steps
- {
- inertiaSmoothing[boneIndex, offsetIndex] = inertiaSmoothing[boneIndex, offsetIndex - 1];
- }
- inertiaSmoothing[boneIndex, 0] = inertia;
- Vector3 smoothedInertia = Vector3.zero;
- for (int offsetIndex = 0; offsetIndex < inertiaSteps; offsetIndex++) // offset inertia steps
- {
- smoothedInertia += inertiaSmoothing[boneIndex, offsetIndex];
- }
- smoothedInertia = smoothedInertia / inertiaSteps;
- //if (boneIndex == 0 && Input.GetKey(KeyCode.Space))
- // Debug.Log(smoothedInertia);
- smoothedInertia = PowVector(smoothedInertia / 20, 3) * 20;
- Vector3 forward = forwardAxis;
- Vector3 forwardDrag = forwardAxis + drag;
- Vector3 forwardInertia = forwardAxis + smoothedInertia;
- Quaternion dragQuaternion = Quaternion.FromToRotation(forward, forwardDrag);
- Quaternion inertiaQuaternion = Quaternion.FromToRotation(forward, forwardInertia);
- velocity[boneIndex] += FixVector(dragQuaternion.eulerAngles) * 2 * deltaTime;
- velocity[boneIndex] += FixVector(inertiaQuaternion.eulerAngles) * 50 * deltaTime;
- velocity[boneIndex] = Vector3.ClampMagnitude(velocity[boneIndex], 1000);
- }
- Vector3 targetPos = pos * Vector3.right * (flexAngle / bones.Length);
- Vector3 springForce = -k * (rotation[boneIndex] - targetPos);
- var dampingForce = damping * velocity[boneIndex];
- var force = springForce - dampingForce;
- var acceleration = force / mass;
- velocity[boneIndex] += acceleration * deltaTime;
- rotation[boneIndex] += velocity[boneIndex] * Time.deltaTime;
- rotation[boneIndex] = Vector3.ClampMagnitude(rotation[boneIndex], 180);
- if (useOffset)
- {
- oldTipPosition[boneIndex] = boneTips[boneIndex].position;
- }
- }
- }
- else
- {
- Debug.LogError("<b>[SteamVR Interaction]</b> finger mass is zero");
- }
- }
- public void ApplyTransforms()
- {
- for (int i = 0; i < bones.Length; i++)
- {
- bones[i].localRotation = startRot[i];
- bones[i].Rotate(rotation[i], Space.Self);
- }
- }
- private Vector3 FixVector(Vector3 ang)
- {
- return new Vector3(FixAngle(ang.x), FixAngle(ang.y), FixAngle(ang.z));
- }
- private float FixAngle(float ang)
- {
- if (ang > 180)
- ang = -360 + ang;
- return ang;
- }
- private Vector3 PowVector(Vector3 vector, float power)
- {
- Vector3 sign = new Vector3(Mathf.Sign(vector.x), Mathf.Sign(vector.y), Mathf.Sign(vector.z));
- vector.x = Mathf.Pow(Mathf.Abs(vector.x), power) * sign.x;
- vector.y = Mathf.Pow(Mathf.Abs(vector.y), power) * sign.y;
- vector.z = Mathf.Pow(Mathf.Abs(vector.z), power) * sign.z;
- return vector;
- }
- }
- public Finger[] fingers;
- public Vector3 constforce;
- private void Start()
- {
- for (int fingerIndex = 0; fingerIndex < fingers.Length; fingerIndex++)
- {
- fingers[fingerIndex].Init();
- fingers[fingerIndex].flexAngle = fingerFlexAngle;
- fingers[fingerIndex].squeezyAction = squeezyAction;
- fingers[fingerIndex].inputSource = inputSource;
- }
- }
- private void Update()
- {
- for (int fingerIndex = 0; fingerIndex < fingers.Length; fingerIndex++)
- {
- fingers[fingerIndex].ApplyForce(constforce);
- fingers[fingerIndex].UpdateFinger(Time.deltaTime);
- fingers[fingerIndex].ApplyTransforms();
- }
- }
- }
- }
|