429 lines
13 KiB
C#
429 lines
13 KiB
C#
|
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
|||
|
|
|||
|
using UnityEngine;
|
|||
|
using System.Collections;
|
|||
|
using System;
|
|||
|
|
|||
|
namespace Valve.VR.InteractionSystem
|
|||
|
{
|
|||
|
public class RenderModel : MonoBehaviour
|
|||
|
{
|
|||
|
public GameObject handPrefab;
|
|||
|
protected GameObject handInstance;
|
|||
|
protected Renderer[] handRenderers;
|
|||
|
public bool displayHandByDefault = true;
|
|||
|
protected SteamVR_Behaviour_Skeleton handSkeleton;
|
|||
|
protected Animator handAnimator;
|
|||
|
|
|||
|
protected string animatorParameterStateName = "AnimationState";
|
|||
|
protected int handAnimatorStateId = -1;
|
|||
|
|
|||
|
[Space]
|
|||
|
|
|||
|
public GameObject controllerPrefab;
|
|||
|
protected GameObject controllerInstance;
|
|||
|
protected Renderer[] controllerRenderers;
|
|||
|
protected SteamVR_RenderModel controllerRenderModel;
|
|||
|
public bool displayControllerByDefault = true;
|
|||
|
protected Material delayedSetMaterial;
|
|||
|
|
|||
|
public event Action onControllerLoaded;
|
|||
|
|
|||
|
protected SteamVR_Events.Action renderModelLoadedAction;
|
|||
|
|
|||
|
protected SteamVR_Input_Sources inputSource;
|
|||
|
|
|||
|
protected void Awake()
|
|||
|
{
|
|||
|
renderModelLoadedAction = SteamVR_Events.RenderModelLoadedAction(OnRenderModelLoaded);
|
|||
|
|
|||
|
InitializeHand();
|
|||
|
|
|||
|
InitializeController();
|
|||
|
}
|
|||
|
|
|||
|
protected void InitializeHand()
|
|||
|
{
|
|||
|
if (handPrefab != null)
|
|||
|
{
|
|||
|
handInstance = GameObject.Instantiate(handPrefab);
|
|||
|
handInstance.transform.parent = this.transform;
|
|||
|
handInstance.transform.localPosition = Vector3.zero;
|
|||
|
handInstance.transform.localRotation = Quaternion.identity;
|
|||
|
handInstance.transform.localScale = handPrefab.transform.localScale;
|
|||
|
handSkeleton = handInstance.GetComponent<SteamVR_Behaviour_Skeleton>();
|
|||
|
handSkeleton.origin = Player.instance.trackingOriginTransform;
|
|||
|
handSkeleton.updatePose = false;
|
|||
|
handSkeleton.skeletonAction.onActiveChange += OnSkeletonActiveChange;
|
|||
|
|
|||
|
handRenderers = handInstance.GetComponentsInChildren<Renderer>();
|
|||
|
if (displayHandByDefault == false)
|
|||
|
SetHandVisibility(false);
|
|||
|
|
|||
|
handAnimator = handInstance.GetComponentInChildren<Animator>();
|
|||
|
|
|||
|
if (handSkeleton.skeletonAction.activeBinding == false && handSkeleton.fallbackPoser == null)
|
|||
|
{
|
|||
|
Debug.LogWarning("Skeleton action: " + handSkeleton.skeletonAction.GetPath() + " is not bound. Your controller may not support SteamVR Skeleton Input. " +
|
|||
|
"Please add a fallback skeleton poser to your skeleton if you want hands to be visible");
|
|||
|
DestroyHand();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected void InitializeController()
|
|||
|
{
|
|||
|
if (controllerPrefab != null)
|
|||
|
{
|
|||
|
controllerInstance = GameObject.Instantiate(controllerPrefab);
|
|||
|
controllerInstance.transform.parent = this.transform;
|
|||
|
controllerInstance.transform.localPosition = Vector3.zero;
|
|||
|
controllerInstance.transform.localRotation = Quaternion.identity;
|
|||
|
controllerInstance.transform.localScale = controllerPrefab.transform.localScale;
|
|||
|
controllerRenderModel = controllerInstance.GetComponent<SteamVR_RenderModel>();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void DestroyHand()
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
handSkeleton.skeletonAction.onActiveChange -= OnSkeletonActiveChange;
|
|||
|
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
Destroy(handInstance);
|
|||
|
handRenderers = null;
|
|||
|
handInstance = null;
|
|||
|
handSkeleton = null;
|
|||
|
handAnimator = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected virtual void OnSkeletonActiveChange(SteamVR_Action_Skeleton changedAction, bool newState)
|
|||
|
{
|
|||
|
if (newState)
|
|||
|
{
|
|||
|
InitializeHand();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DestroyHand();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
protected void OnEnable()
|
|||
|
{
|
|||
|
renderModelLoadedAction.enabled = true;
|
|||
|
}
|
|||
|
|
|||
|
protected void OnDisable()
|
|||
|
{
|
|||
|
renderModelLoadedAction.enabled = false;
|
|||
|
}
|
|||
|
|
|||
|
protected void OnDestroy()
|
|||
|
{
|
|||
|
DestroyHand();
|
|||
|
}
|
|||
|
|
|||
|
public SteamVR_Behaviour_Skeleton GetSkeleton()
|
|||
|
{
|
|||
|
return handSkeleton;
|
|||
|
}
|
|||
|
|
|||
|
public virtual void SetInputSource(SteamVR_Input_Sources newInputSource)
|
|||
|
{
|
|||
|
inputSource = newInputSource;
|
|||
|
if (controllerRenderModel != null)
|
|||
|
controllerRenderModel.SetInputSource(inputSource);
|
|||
|
}
|
|||
|
|
|||
|
public virtual void OnHandInitialized(int deviceIndex)
|
|||
|
{
|
|||
|
controllerRenderModel.SetInputSource(inputSource);
|
|||
|
controllerRenderModel.SetDeviceIndex(deviceIndex);
|
|||
|
}
|
|||
|
|
|||
|
public void MatchHandToTransform(Transform match)
|
|||
|
{
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
handInstance.transform.position = match.transform.position;
|
|||
|
handInstance.transform.rotation = match.transform.rotation;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetHandPosition(Vector3 newPosition)
|
|||
|
{
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
handInstance.transform.position = newPosition;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetHandRotation(Quaternion newRotation)
|
|||
|
{
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
handInstance.transform.rotation = newRotation;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public Vector3 GetHandPosition()
|
|||
|
{
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
return handInstance.transform.position;
|
|||
|
}
|
|||
|
|
|||
|
return Vector3.zero;
|
|||
|
}
|
|||
|
|
|||
|
public Quaternion GetHandRotation()
|
|||
|
{
|
|||
|
if (handInstance != null)
|
|||
|
{
|
|||
|
return handInstance.transform.rotation;
|
|||
|
}
|
|||
|
|
|||
|
return Quaternion.identity;
|
|||
|
}
|
|||
|
|
|||
|
private void OnRenderModelLoaded(SteamVR_RenderModel loadedRenderModel, bool success)
|
|||
|
{
|
|||
|
if (controllerRenderModel == loadedRenderModel)
|
|||
|
{
|
|||
|
controllerRenderers = controllerInstance.GetComponentsInChildren<Renderer>();
|
|||
|
if (displayControllerByDefault == false)
|
|||
|
SetControllerVisibility(false);
|
|||
|
|
|||
|
if (delayedSetMaterial != null)
|
|||
|
SetControllerMaterial(delayedSetMaterial);
|
|||
|
|
|||
|
if (onControllerLoaded != null)
|
|||
|
onControllerLoaded.Invoke();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetVisibility(bool state, bool overrideDefault = false)
|
|||
|
{
|
|||
|
if (state == false || displayControllerByDefault || overrideDefault)
|
|||
|
SetControllerVisibility(state);
|
|||
|
|
|||
|
if (state == false || displayHandByDefault || overrideDefault)
|
|||
|
SetHandVisibility(state);
|
|||
|
}
|
|||
|
|
|||
|
public void Show(bool overrideDefault = false)
|
|||
|
{
|
|||
|
SetVisibility(true, overrideDefault);
|
|||
|
}
|
|||
|
|
|||
|
public void Hide()
|
|||
|
{
|
|||
|
SetVisibility(false);
|
|||
|
}
|
|||
|
|
|||
|
public virtual void SetMaterial(Material material)
|
|||
|
{
|
|||
|
SetControllerMaterial(material);
|
|||
|
SetHandMaterial(material);
|
|||
|
}
|
|||
|
|
|||
|
public void SetControllerMaterial(Material material)
|
|||
|
{
|
|||
|
if (controllerRenderers == null)
|
|||
|
{
|
|||
|
delayedSetMaterial = material;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (int rendererIndex = 0; rendererIndex < controllerRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
controllerRenderers[rendererIndex].material = material;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetHandMaterial(Material material)
|
|||
|
{
|
|||
|
for (int rendererIndex = 0; rendererIndex < handRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
handRenderers[rendererIndex].material = material;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetControllerVisibility(bool state, bool permanent = false)
|
|||
|
{
|
|||
|
if (permanent)
|
|||
|
displayControllerByDefault = state;
|
|||
|
|
|||
|
if (controllerRenderers == null)
|
|||
|
return;
|
|||
|
|
|||
|
for (int rendererIndex = 0; rendererIndex < controllerRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
controllerRenderers[rendererIndex].enabled = state;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetHandVisibility(bool state, bool permanent = false)
|
|||
|
{
|
|||
|
if (permanent)
|
|||
|
displayHandByDefault = state;
|
|||
|
|
|||
|
if (handRenderers == null)
|
|||
|
return;
|
|||
|
|
|||
|
for (int rendererIndex = 0; rendererIndex < handRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
handRenderers[rendererIndex].enabled = state;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool IsHandVisibile()
|
|||
|
{
|
|||
|
if (handRenderers == null)
|
|||
|
return false;
|
|||
|
|
|||
|
for (int rendererIndex = 0; rendererIndex < handRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
if (handRenderers[rendererIndex].enabled)
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsControllerVisibile()
|
|||
|
{
|
|||
|
if (controllerRenderers == null)
|
|||
|
return false;
|
|||
|
|
|||
|
for (int rendererIndex = 0; rendererIndex < controllerRenderers.Length; rendererIndex++)
|
|||
|
{
|
|||
|
if (controllerRenderers[rendererIndex].enabled)
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public Transform GetBone(int boneIndex)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
return handSkeleton.GetBone(boneIndex);
|
|||
|
}
|
|||
|
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
public Vector3 GetBonePosition(int boneIndex, bool local = false)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
return handSkeleton.GetBonePosition(boneIndex, local);
|
|||
|
}
|
|||
|
|
|||
|
return Vector3.zero;
|
|||
|
}
|
|||
|
|
|||
|
public Vector3 GetControllerPosition(string componentName = null)
|
|||
|
{
|
|||
|
if (controllerRenderModel != null)
|
|||
|
return controllerRenderModel.GetComponentTransform(componentName).position;
|
|||
|
|
|||
|
return Vector3.zero;
|
|||
|
}
|
|||
|
|
|||
|
public Quaternion GetBoneRotation(int boneIndex, bool local = false)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
return handSkeleton.GetBoneRotation(boneIndex, local);
|
|||
|
}
|
|||
|
|
|||
|
return Quaternion.identity;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public void SetSkeletonRangeOfMotion(EVRSkeletalMotionRange newRangeOfMotion, float blendOverSeconds = 0.1f)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
handSkeleton.SetRangeOfMotion(newRangeOfMotion, blendOverSeconds);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public EVRSkeletalMotionRange GetSkeletonRangeOfMotion
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
return handSkeleton.rangeOfMotion;
|
|||
|
else
|
|||
|
return EVRSkeletalMotionRange.WithController;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetTemporarySkeletonRangeOfMotion(SkeletalMotionRangeChange temporaryRangeOfMotionChange, float blendOverSeconds = 0.1f)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
handSkeleton.SetTemporaryRangeOfMotion((EVRSkeletalMotionRange)temporaryRangeOfMotionChange, blendOverSeconds);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ResetTemporarySkeletonRangeOfMotion(float blendOverSeconds = 0.1f)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
handSkeleton.ResetTemporaryRangeOfMotion(blendOverSeconds);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetAnimationState(int stateValue)
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
if (handSkeleton.isBlending == false)
|
|||
|
handSkeleton.BlendToAnimation();
|
|||
|
|
|||
|
if (CheckAnimatorInit())
|
|||
|
handAnimator.SetInteger(handAnimatorStateId, stateValue);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void StopAnimation()
|
|||
|
{
|
|||
|
if (handSkeleton != null)
|
|||
|
{
|
|||
|
if (handSkeleton.isBlending == false)
|
|||
|
handSkeleton.BlendToSkeleton();
|
|||
|
|
|||
|
if (CheckAnimatorInit())
|
|||
|
handAnimator.SetInteger(handAnimatorStateId, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool CheckAnimatorInit()
|
|||
|
{
|
|||
|
if (handAnimatorStateId == -1 && handAnimator != null)
|
|||
|
{
|
|||
|
if (handAnimator.gameObject.activeInHierarchy && handAnimator.isInitialized)
|
|||
|
{
|
|||
|
AnimatorControllerParameter[] parameters = handAnimator.parameters;
|
|||
|
for (int parameterIndex = 0; parameterIndex < parameters.Length; parameterIndex++)
|
|||
|
{
|
|||
|
if (string.Equals(parameters[parameterIndex].name, animatorParameterStateName, StringComparison.CurrentCultureIgnoreCase))
|
|||
|
handAnimatorStateId = parameters[parameterIndex].nameHash;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return handAnimatorStateId != -1 && handAnimator != null && handAnimator.isInitialized;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|