You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			233 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			233 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C#
		
	
//======= 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();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |