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.
		
		
		
		
		
			
		
			
				
	
	
		
			294 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			294 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C#
		
	
using NaughtyAttributes;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using UnityEngine;
 | 
						|
 | 
						|
namespace Autohand {
 | 
						|
    public class HandProjector : MonoBehaviour {
 | 
						|
        [Header("References")]
 | 
						|
        public Hand hand;
 | 
						|
        [Tooltip("This should be a copy of the hand with the desired visual setup for your projection hand")]
 | 
						|
        public Hand handProjection;
 | 
						|
        [Tooltip("The Object(s) under your Hand that contain the MeshRenderer Component(s)")]
 | 
						|
        public Transform[] handProjectionVisuals;
 | 
						|
 | 
						|
        [Tooltip("Smoothing speed, turning too high could cause jitters")]
 | 
						|
        public float speed = 15f;
 | 
						|
 | 
						|
        [Tooltip("If true everything in the hand Vvisuals will be disabled/hidden when projection hand is showing")]
 | 
						|
        public bool hideHand;
 | 
						|
        [ShowIf("hideHand")]
 | 
						|
        [Tooltip("The Object(s) under your main hand (not the projection hand) that contain the MeshRenderer Component(s)")]
 | 
						|
        public Transform[] handVisuals;
 | 
						|
 | 
						|
        [Tooltip("Should the projection interpolate between the hand pose and the projected grab pose based on the grip input axis")]
 | 
						|
        public bool useGrabTransition;
 | 
						|
        [EnableIf("useGrabTransition")]
 | 
						|
        [Tooltip("This offsets the grab transistion by this percent when active [0-1 range]")]
 | 
						|
        public float grabTransitionOffset = 0;
 | 
						|
        [EnableIf("useGrabTransition")]
 | 
						|
        [Tooltip("This sets the position of the hand based on its [(gripAxis + grabTransitionOffset) * grabDistanceMultiplyer] -> gripAxis is set on the HandControllerLink component on the main hand")]
 | 
						|
        public float grabDistanceMultiplyer = 2f;
 | 
						|
        [Tooltip("This sets the pose of the hand based on its [(gripAxis + grabTransitionOffset) * grabDistanceMultiplyer] -> gripAxis is set on the HandControllerLink component on the main hand")]
 | 
						|
        [EnableIf("useGrabTransition")]
 | 
						|
        public float grabTransitionMultiplyer = 2f;
 | 
						|
        [DisableIf("useGrabTransition")]
 | 
						|
        [Tooltip("This offsets the highlight by this percent when active [0-1 range]")]
 | 
						|
        public float grabPercent = 1f;
 | 
						|
 | 
						|
 | 
						|
        [Header("Events")]
 | 
						|
        public UnityHandGrabEvent OnStartProjection;
 | 
						|
        public UnityHandGrabEvent OnEndProjection;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        HandPoseData lastProjectionPose;
 | 
						|
        HandPoseData newProjectionPose;
 | 
						|
        Vector3 lastProjectionPosition;
 | 
						|
        Quaternion lastProjectionRotation;
 | 
						|
 | 
						|
        Grabbable target;
 | 
						|
        float startMass = 0;
 | 
						|
        float minGrabTime = 0;
 | 
						|
        float currAmount;
 | 
						|
        bool tryingGrab = false;
 | 
						|
 | 
						|
        void OnEnable() {
 | 
						|
            if(handProjection.body == null)
 | 
						|
                handProjection.body = handProjection.GetComponent<Rigidbody>();
 | 
						|
            if(hand.body == null)
 | 
						|
                hand.body = hand.GetComponent<Rigidbody>();
 | 
						|
            handProjection.body.detectCollisions = false;
 | 
						|
            handProjection.body.mass = 0;
 | 
						|
 | 
						|
            handProjection.enableMovement = false;
 | 
						|
            handProjection.usingHighlight = false;
 | 
						|
            handProjection.disableIK = true;
 | 
						|
 | 
						|
            handProjection.followPositionStrength = 0;
 | 
						|
            handProjection.followRotationStrength = 0;
 | 
						|
            handProjection.swayStrength = 0;
 | 
						|
            handProjection.disableIK = true;
 | 
						|
            handProjection.usingHighlight = false;
 | 
						|
            handProjection.usingPoseAreas = false;
 | 
						|
            startMass = hand.body.mass;
 | 
						|
            minGrabTime = hand.minGrabTime;
 | 
						|
 | 
						|
            lastProjectionPosition = hand.transform.localPosition;
 | 
						|
            lastProjectionRotation = hand.transform.localRotation;
 | 
						|
            lastProjectionPose = hand.GetHandPose();
 | 
						|
 | 
						|
            hand.OnBeforeGrabbed += OnBeforeGrab;
 | 
						|
            hand.OnGrabbed += OnGrab;
 | 
						|
            hand.OnBeforeReleased += OnRelease;
 | 
						|
            hand.OnTriggerGrab += OnTriggerGrab;
 | 
						|
        }
 | 
						|
 | 
						|
        void OnDisable() {
 | 
						|
            ShowProjection(false);
 | 
						|
            hand.OnBeforeGrabbed -= OnBeforeGrab;
 | 
						|
            hand.OnGrabbed -= OnGrab;
 | 
						|
            hand.OnBeforeReleased -= OnRelease;
 | 
						|
            hand.OnTriggerGrab -= OnTriggerGrab;
 | 
						|
        }
 | 
						|
 | 
						|
        void OnTriggerGrab(Hand hand, Grabbable grab) {
 | 
						|
            tryingGrab = true;
 | 
						|
        }
 | 
						|
 | 
						|
        void OnBeforeGrab(Hand hand, Grabbable grab) {
 | 
						|
 | 
						|
            if(hideHand) {
 | 
						|
                lastProjectionPose.SetFingerPose(hand);
 | 
						|
                hand.transform.position = handProjection.transform.position;
 | 
						|
                hand.transform.rotation = handProjection.transform.rotation;
 | 
						|
                hand.body.position = hand.transform.position;
 | 
						|
                hand.body.rotation = hand.transform.rotation;
 | 
						|
 | 
						|
                hand.minGrabTime = 0f;
 | 
						|
            }
 | 
						|
 | 
						|
            ShowProjection(false);
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGrab(Hand hand, Grabbable grab) {
 | 
						|
 | 
						|
            if(useGrabTransition) {
 | 
						|
                hand.minGrabTime = minGrabTime;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnRelease(Hand hand, Grabbable grab) {
 | 
						|
            lastProjectionPose = hand.GetHandPose();
 | 
						|
            lastProjectionPose.SetFingerPose(handProjection);
 | 
						|
            lastProjectionPosition = hand.transform.localPosition;
 | 
						|
            lastProjectionRotation = hand.transform.localRotation;
 | 
						|
            handProjection.transform.position = hand.transform.position;
 | 
						|
            handProjection.transform.rotation = hand.transform.rotation;
 | 
						|
            handProjection.body.position = handProjection.transform.position;
 | 
						|
            handProjection.body.rotation = handProjection.transform.rotation;
 | 
						|
 | 
						|
            if(hideHand) {
 | 
						|
                hand.minGrabTime = minGrabTime;
 | 
						|
                for(int i = 0; i < handProjection.fingers.Length; i++)
 | 
						|
                    handProjection.fingers[i].SetCurrentFingerBend(hand.fingers[i].GetLastHitBend());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void LateUpdate() {
 | 
						|
            if(tryingGrab && hand.GetTriggerAxis() < 0.35f)
 | 
						|
                tryingGrab = false;
 | 
						|
            
 | 
						|
 | 
						|
            SetTarget(hand.lookingAtObj);
 | 
						|
            ShowProjection(IsProjectionActive());
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void OnProjectionStart(Hand projectionHand, Grabbable target) {
 | 
						|
            OnStartProjection?.Invoke(projectionHand, target);
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void OnProjectionEnd(Hand projectionHand, Grabbable target) {
 | 
						|
            OnEndProjection?.Invoke(projectionHand, target);
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void ShowProjection(bool show) {
 | 
						|
            for(int i = 0; i < handProjectionVisuals.Length; i++)
 | 
						|
                handProjectionVisuals[i].gameObject.SetActive(show);
 | 
						|
 | 
						|
            if(hideHand) {
 | 
						|
                for(int i = 0; i < handVisuals.Length; i++)
 | 
						|
                    handVisuals[i].gameObject.SetActive(!show);
 | 
						|
                if(show)
 | 
						|
                    hand.body.mass = 0;
 | 
						|
                else
 | 
						|
                    hand.body.mass = startMass;
 | 
						|
            }
 | 
						|
 | 
						|
            if(show) {
 | 
						|
                var targetHit = hand.GetHighlightHit();
 | 
						|
                if(targetHit.collider != null) {
 | 
						|
 | 
						|
                    if(!hand.CanGrab(target)) {
 | 
						|
                        ShowProjection(false);
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
 | 
						|
                    var amount = useGrabTransition ? hand.grabCurve.Evaluate(hand.GetTriggerAxis() * grabTransitionMultiplyer + grabTransitionOffset) : grabPercent;
 | 
						|
                    currAmount = Mathf.MoveTowards(currAmount, amount, Time.deltaTime * speed);
 | 
						|
                    var newSpeed = Mathf.Lerp(speed, speed / 4f, hand.GetTriggerAxis());
 | 
						|
                    if(hideHand)
 | 
						|
                        hand.body.mass = Mathf.Lerp(startMass, 0, Mathf.Pow(amount * 2, 2));
 | 
						|
 | 
						|
                    //Do new pose
 | 
						|
                    GrabbablePose grabPose;
 | 
						|
                    handProjection.transform.localPosition = hand.transform.localPosition;
 | 
						|
                    handProjection.transform.localRotation = hand.transform.localRotation;
 | 
						|
                    if(handProjection.GetGrabPose(target, out grabPose)) {
 | 
						|
                        grabPose.SetHandPose(handProjection, true);
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        handProjection.transform.position -= handProjection.palmTransform.forward * 0.08f;
 | 
						|
                        handProjection.body.position = handProjection.transform.position;
 | 
						|
                        handProjection.AutoPose(targetHit, target);
 | 
						|
                    }
 | 
						|
                    newProjectionPose = handProjection.GetHandPose();
 | 
						|
                    Vector3 targetPos;
 | 
						|
                    Quaternion targetRot;
 | 
						|
 | 
						|
                    if(useGrabTransition && (target.grabType == HandGrabType.GrabbableToHand || (target.grabType == HandGrabType.Default && hand.grabType == GrabType.GrabbableToHand))) {
 | 
						|
                        targetPos = hand.transform.localPosition;
 | 
						|
                        targetRot = hand.transform.localRotation;
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        targetPos = Vector3.Lerp(hand.transform.localPosition, handProjection.transform.localPosition, currAmount * grabDistanceMultiplyer);
 | 
						|
                        targetRot = Quaternion.Lerp(hand.transform.localRotation, handProjection.transform.localRotation, currAmount * grabDistanceMultiplyer);
 | 
						|
                    }
 | 
						|
 | 
						|
 | 
						|
                    //Visual Adjustments
 | 
						|
                    if(grabPose == null)
 | 
						|
                        foreach(var finger in handProjection.fingers)
 | 
						|
                            finger.SetFingerBend(Mathf.Clamp01(finger.GetLastHitBend() - 0.1f));
 | 
						|
                    else {
 | 
						|
                        foreach(var finger in handProjection.fingers)
 | 
						|
                            finger.SetFingerBend(handProjection.gripOffset);
 | 
						|
                    }
 | 
						|
 | 
						|
 | 
						|
                    //Interpolate Fingers
 | 
						|
                    var postGrabPose = HandPoseData.LerpPose(hand.GetHandPose(), newProjectionPose, Mathf.Clamp01(currAmount - 0.33f)*1.5f);
 | 
						|
                    HandPoseData.LerpPose(lastProjectionPose, postGrabPose, speed * Time.deltaTime).SetFingerPose(handProjection);
 | 
						|
 | 
						|
                    if(hand.GetTriggerAxis() > 0.1f || !hideHand) {
 | 
						|
                        //Interpolate Position
 | 
						|
                        handProjection.transform.localPosition = Vector3.Lerp(lastProjectionPosition, targetPos, newSpeed * Time.deltaTime);
 | 
						|
                        handProjection.transform.localRotation = Quaternion.Lerp(lastProjectionRotation, targetRot, newSpeed * Time.deltaTime);
 | 
						|
                    }
 | 
						|
                    else{
 | 
						|
                        handProjection.transform.localPosition = hand.transform.localPosition;
 | 
						|
                        handProjection.transform.localRotation = hand.transform.localRotation;
 | 
						|
                        lastProjectionPose = hand.GetHandPose();
 | 
						|
                        lastProjectionPose.SetFingerPose(handProjection);
 | 
						|
                    }
 | 
						|
                    handProjection.body.position = handProjection.transform.position;
 | 
						|
                    handProjection.body.rotation = handProjection.transform.rotation;
 | 
						|
 | 
						|
                    lastProjectionPosition = handProjection.transform.localPosition;
 | 
						|
                    lastProjectionRotation = handProjection.transform.localRotation;
 | 
						|
                    lastProjectionPose = handProjection.GetHandPose();
 | 
						|
                }
 | 
						|
                else if(!hand.IsGrabbing()){
 | 
						|
                    handProjection.transform.localPosition = hand.transform.localPosition;
 | 
						|
                    handProjection.transform.localRotation = hand.transform.localRotation;
 | 
						|
                    lastProjectionPosition = hand.transform.localPosition;
 | 
						|
                    lastProjectionRotation = hand.transform.localRotation;
 | 
						|
                    lastProjectionPose = hand.GetHandPose();
 | 
						|
                    lastProjectionPose.SetFingerPose(handProjection);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else if(useGrabTransition){
 | 
						|
                handProjection.transform.localPosition = hand.transform.localPosition;
 | 
						|
                handProjection.transform.localRotation = hand.transform.localRotation;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void SetTarget(Grabbable newTarget) {
 | 
						|
            if(newTarget != null && !hand.CanGrab(newTarget))
 | 
						|
                newTarget = null;
 | 
						|
 | 
						|
            if(hand.holdingObj != null || newTarget == null) {
 | 
						|
                if(target != null) {
 | 
						|
                    OnProjectionEnd(handProjection, target);
 | 
						|
 | 
						|
                    lastProjectionPosition = hand.transform.localPosition;
 | 
						|
                    lastProjectionRotation = hand.transform.localRotation;
 | 
						|
                    handProjection.transform.position = hand.transform.position;
 | 
						|
                    handProjection.transform.rotation = hand.transform.rotation;
 | 
						|
                    handProjection.body.position = handProjection.transform.position;
 | 
						|
                    handProjection.body.rotation = handProjection.transform.rotation;
 | 
						|
                }
 | 
						|
 | 
						|
                target = null;
 | 
						|
            }
 | 
						|
 | 
						|
            if(newTarget != target) {
 | 
						|
                if(target != null)
 | 
						|
                    OnProjectionEnd(handProjection, target);
 | 
						|
                target = newTarget;
 | 
						|
                OnProjectionStart(handProjection, target);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        bool IsProjectionActive() {
 | 
						|
            return target != null && hand.holdingObj == null && !hand.IsGrabbing() && !tryingGrab;
 | 
						|
        }
 | 
						|
    }
 | 
						|
} |