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#
6 months ago
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|