// Base Pointer Renderer|PointerRenderers|10010
|
|
namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
#if UNITY_5_5_OR_NEWER
|
|
using UnityEngine.AI;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Provides a base that all pointer renderers can inherit from.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// **Script Usage:**
|
|
/// > This is an abstract class that is to be inherited to a concrete class that provides pointer renderer functionality, therefore this script should not be directly used.
|
|
/// </remarks>
|
|
public abstract class VRTK_BasePointerRenderer : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// States of Pointer Visibility.
|
|
/// </summary>
|
|
public enum VisibilityStates
|
|
{
|
|
/// <summary>
|
|
/// Only shows the object when the pointer is active.
|
|
/// </summary>
|
|
OnWhenActive,
|
|
/// <summary>
|
|
/// Ensures the object is always.
|
|
/// </summary>
|
|
AlwaysOn,
|
|
/// <summary>
|
|
/// Ensures the object beam is never visible.
|
|
/// </summary>
|
|
AlwaysOff
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class PointerOriginSmoothingSettings
|
|
{
|
|
[Tooltip("Whether or not to smooth the position of the pointer origin when positioning the pointer tip.")]
|
|
public bool smoothsPosition;
|
|
[Tooltip("The maximum allowed distance between the unsmoothed pointer origin and the smoothed pointer origin per frame to use for smoothing.")]
|
|
public float maxAllowedPerFrameDistanceDifference = 0.003f;
|
|
|
|
[Tooltip("Whether or not to smooth the rotation of the pointer origin when positioning the pointer tip.")]
|
|
public bool smoothsRotation;
|
|
[Tooltip("The maximum allowed angle between the unsmoothed pointer origin and the smoothed pointer origin per frame to use for smoothing.")]
|
|
public float maxAllowedPerFrameAngleDifference = 1.5f;
|
|
}
|
|
|
|
[Header("Renderer Supplement Settings")]
|
|
|
|
[Tooltip("An optional Play Area Cursor generator to add to the destination position of the pointer tip.")]
|
|
public VRTK_PlayAreaCursor playareaCursor;
|
|
[Tooltip("A custom VRTK_PointerDirectionIndicator to use to determine the rotation given to the destination set event.")]
|
|
public VRTK_PointerDirectionIndicator directionIndicator;
|
|
|
|
[Header("General Renderer Settings")]
|
|
|
|
[Tooltip("A custom raycaster to use for the pointer's raycasts to ignore.")]
|
|
public VRTK_CustomRaycast customRaycast;
|
|
[Tooltip("Specifies the smoothing to be applied to the pointer origin when positioning the pointer tip.")]
|
|
public PointerOriginSmoothingSettings pointerOriginSmoothingSettings = new PointerOriginSmoothingSettings();
|
|
|
|
[Header("General Appearance Settings")]
|
|
|
|
[Tooltip("The colour to change the pointer materials when the pointer collides with a valid object. Set to `Color.clear` to bypass changing material colour on valid collision.")]
|
|
public Color validCollisionColor = Color.green;
|
|
[Tooltip("The colour to change the pointer materials when the pointer is not colliding with anything or with an invalid object. Set to `Color.clear` to bypass changing material colour on invalid collision.")]
|
|
public Color invalidCollisionColor = Color.red;
|
|
|
|
[Tooltip("Determines when the main tracer of the pointer renderer will be visible.")]
|
|
public VisibilityStates tracerVisibility = VisibilityStates.OnWhenActive;
|
|
[Tooltip("Determines when the cursor/tip of the pointer renderer will be visible.")]
|
|
public VisibilityStates cursorVisibility = VisibilityStates.OnWhenActive;
|
|
|
|
protected const float BEAM_ADJUST_OFFSET = 0.0001f;
|
|
|
|
protected VRTK_Pointer controllingPointer;
|
|
protected RaycastHit destinationHit = new RaycastHit();
|
|
protected Material defaultMaterial;
|
|
protected Color previousColor;
|
|
protected Color currentColor;
|
|
|
|
protected VRTK_PolicyList invalidListPolicy;
|
|
protected VRTK_NavMeshData navMeshData;
|
|
protected bool headsetPositionCompensation;
|
|
|
|
protected GameObject objectInteractor;
|
|
protected GameObject objectInteractorAttachPoint;
|
|
protected GameObject pointerOriginTransformFollowGameObject;
|
|
protected VRTK_TransformFollow pointerOriginTransformFollow;
|
|
protected VRTK_InteractGrab controllerGrabScript;
|
|
protected Rigidbody savedAttachPoint;
|
|
protected bool attachedToInteractorAttachPoint = false;
|
|
protected float savedBeamLength = 0f;
|
|
protected HashSet<GameObject> makeRendererVisible = new HashSet<GameObject>();
|
|
|
|
protected bool tracerVisible;
|
|
protected bool cursorVisible;
|
|
protected LayerMask defaultIgnoreLayer = Physics.IgnoreRaycastLayer;
|
|
|
|
protected SDK_BaseController.ControllerHand cachedAttachedHand = SDK_BaseController.ControllerHand.None;
|
|
protected Transform cachedPointerAttachPoint = null;
|
|
|
|
/// <summary>
|
|
/// The GetPointerObjects returns an array of the auto generated GameObjects associated with the pointer.
|
|
/// </summary>
|
|
/// <returns>An array of pointer auto generated GameObjects.</returns>
|
|
public abstract GameObject[] GetPointerObjects();
|
|
|
|
/// <summary>
|
|
/// The InitalizePointer method is used to set up the state of the pointer renderer.
|
|
/// </summary>
|
|
/// <param name="givenPointer">The VRTK_Pointer that is controlling the pointer renderer.</param>
|
|
/// <param name="givenInvalidListPolicy">The VRTK_PolicyList for managing valid and invalid pointer locations.</param>
|
|
/// <param name="givenNavMeshCheckDistance">The given distance from a nav mesh that the pointer can be to be valid.</param>
|
|
/// <param name="givenHeadsetPositionCompensation">Determines whether the play area cursor will take the headset position within the play area into account when being displayed.</param>
|
|
[Obsolete("`VRTK_BasePointerRenderer.InitalizePointer(givenPointer, givenInvalidListPolicy, givenNavMeshCheckDistance, givenHeadsetPositionCompensation)` has been replaced with the method `VRTK_BasePointerRenderer.InitalizePointer(givenPointer, givenInvalidListPolicy, givenNavMeshData, givenHeadsetPositionCompensation)`. This method will be removed in a future version of VRTK.")]
|
|
public virtual void InitalizePointer(VRTK_Pointer givenPointer, VRTK_PolicyList givenInvalidListPolicy, float givenNavMeshCheckDistance, bool givenHeadsetPositionCompensation)
|
|
{
|
|
VRTK_NavMeshData givenData = gameObject.AddComponent<VRTK_NavMeshData>();
|
|
givenData.distanceLimit = givenNavMeshCheckDistance;
|
|
InitalizePointer(givenPointer, givenInvalidListPolicy, givenData, givenHeadsetPositionCompensation);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The InitalizePointer method is used to set up the state of the pointer renderer.
|
|
/// </summary>
|
|
/// <param name="givenPointer">The VRTK_Pointer that is controlling the pointer renderer.</param>
|
|
/// <param name="givenInvalidListPolicy">The VRTK_PolicyList for managing valid and invalid pointer locations.</param>
|
|
/// <param name="givenNavMeshData">The NavMeshData object that contains the Nav Mesh restriction options.</param>
|
|
/// <param name="givenHeadsetPositionCompensation">Determines whether the play area cursor will take the headset position within the play area into account when being displayed.</param>
|
|
public virtual void InitalizePointer(VRTK_Pointer givenPointer, VRTK_PolicyList givenInvalidListPolicy, VRTK_NavMeshData givenNavMeshData, bool givenHeadsetPositionCompensation)
|
|
{
|
|
controllingPointer = givenPointer;
|
|
invalidListPolicy = givenInvalidListPolicy;
|
|
navMeshData = givenNavMeshData;
|
|
headsetPositionCompensation = givenHeadsetPositionCompensation;
|
|
|
|
if (controllingPointer != null && controllingPointer.interactWithObjects && controllingPointer.controllerEvents != null && objectInteractor == null)
|
|
{
|
|
controllerGrabScript = controllingPointer.controllerEvents.GetComponentInChildren<VRTK_InteractGrab>();
|
|
CreateObjectInteractor();
|
|
}
|
|
SetupDirectionIndicator();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The ResetPointerObjects method is used to destroy any existing pointer objects and recreate them at runtime.
|
|
/// </summary>
|
|
public virtual void ResetPointerObjects()
|
|
{
|
|
DestroyPointerOriginTransformFollow();
|
|
DestroyPointerObjects();
|
|
CreatePointerOriginTransformFollow();
|
|
CreatePointerObjects();
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Toggle Method is used to enable or disable the pointer renderer.
|
|
/// </summary>
|
|
/// <param name="pointerState">The activation state of the pointer.</param>
|
|
/// <param name="actualState">The actual state of the activation button press.</param>
|
|
public virtual void Toggle(bool pointerState, bool actualState)
|
|
{
|
|
if (pointerState)
|
|
{
|
|
destinationHit = new RaycastHit();
|
|
}
|
|
else if (controllingPointer != null)
|
|
{
|
|
controllingPointer.ResetActivationTimer();
|
|
PointerExit(destinationHit);
|
|
}
|
|
|
|
ToggleInteraction(pointerState);
|
|
ToggleRenderer(pointerState, actualState);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The ToggleInteraction method is used to enable or disable the controller extension interactions.
|
|
/// </summary>
|
|
/// <param name="state">If true then the object interactor will be enabled.</param>
|
|
public virtual void ToggleInteraction(bool state)
|
|
{
|
|
ToggleObjectInteraction(state);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The UpdateRenderer method is used to run an Update routine on the pointer.
|
|
/// </summary>
|
|
public virtual void UpdateRenderer()
|
|
{
|
|
if (playareaCursor != null)
|
|
{
|
|
playareaCursor.SetHeadsetPositionCompensation(headsetPositionCompensation);
|
|
playareaCursor.ToggleState(IsCursorVisible());
|
|
}
|
|
|
|
if (directionIndicator != null)
|
|
{
|
|
UpdateDirectionIndicator();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The GetDestinationHit method is used to get the RaycastHit of the pointer destination.
|
|
/// </summary>
|
|
/// <returns>The RaycastHit containing the information where the pointer is hitting.</returns>
|
|
public virtual RaycastHit GetDestinationHit()
|
|
{
|
|
return destinationHit;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The ValidPlayArea method is used to determine if there is a valid play area and if it has had any collisions.
|
|
/// </summary>
|
|
/// <returns>Returns true if there is a valid play area and no collisions. Returns false if there is no valid play area or there is but with a collision detected.</returns>
|
|
public virtual bool ValidPlayArea()
|
|
{
|
|
return (playareaCursor == null || !playareaCursor.IsActive() || !playareaCursor.HasCollided());
|
|
}
|
|
|
|
/// <summary>
|
|
/// The IsVisible method determines if the pointer renderer is at all visible by checking the state of the tracer and the cursor.
|
|
/// </summary>
|
|
/// <returns>Returns true if either the tracer or cursor renderers are visible. Returns false if none are visible.</returns>
|
|
public virtual bool IsVisible()
|
|
{
|
|
return (IsTracerVisible() || IsCursorVisible());
|
|
}
|
|
|
|
/// <summary>
|
|
/// The IsTracerVisible method determines if the pointer tracer renderer is visible.
|
|
/// </summary>
|
|
/// <returns>Returns true if the tracer renderers are visible.</returns>
|
|
public virtual bool IsTracerVisible()
|
|
{
|
|
return (tracerVisibility == VisibilityStates.AlwaysOn || tracerVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The IsCursorVisible method determines if the pointer cursor renderer is visible.
|
|
/// </summary>
|
|
/// <returns>Returns true if the cursor renderers are visible.</returns>
|
|
public virtual bool IsCursorVisible()
|
|
{
|
|
return (cursorVisibility == VisibilityStates.AlwaysOn || cursorVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The IsValidCollision method determines if the pointer is currently in it's valid collision state.
|
|
/// </summary>
|
|
/// <returns>Returns true if the pointer is in a valid collision, returns false if the pointer is in an invalid collision state.</returns>
|
|
public virtual bool IsValidCollision()
|
|
{
|
|
return (currentColor != invalidCollisionColor);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The GetObjectInteractor method returns the auto generated GameObject that acts as the controller extension for interacting with objects.
|
|
/// </summary>
|
|
/// <returns>The auto generated object interactor GameObject.</returns>
|
|
/// <returns></returns>
|
|
public virtual GameObject GetObjectInteractor()
|
|
{
|
|
return objectInteractor;
|
|
}
|
|
|
|
protected abstract void CreatePointerObjects();
|
|
protected abstract void DestroyPointerObjects();
|
|
protected abstract void ToggleRenderer(bool pointerState, bool actualState);
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
|
|
}
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
cachedPointerAttachPoint = null;
|
|
cachedAttachedHand = SDK_BaseController.ControllerHand.None;
|
|
defaultMaterial = Resources.Load("WorldPointer") as Material;
|
|
makeRendererVisible.Clear();
|
|
CreatePointerOriginTransformFollow();
|
|
CreatePointerObjects();
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
DestroyPointerObjects();
|
|
if (objectInteractor != null)
|
|
{
|
|
Destroy(objectInteractor);
|
|
}
|
|
controllerGrabScript = null;
|
|
DestroyPointerOriginTransformFollow();
|
|
}
|
|
|
|
protected virtual void OnDestroy()
|
|
{
|
|
VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
|
|
}
|
|
|
|
protected virtual void OnValidate()
|
|
{
|
|
pointerOriginSmoothingSettings.maxAllowedPerFrameDistanceDifference = Mathf.Max(0.0001f, pointerOriginSmoothingSettings.maxAllowedPerFrameDistanceDifference);
|
|
pointerOriginSmoothingSettings.maxAllowedPerFrameAngleDifference = Mathf.Max(0.0001f, pointerOriginSmoothingSettings.maxAllowedPerFrameAngleDifference);
|
|
}
|
|
|
|
protected virtual void FixedUpdate()
|
|
{
|
|
if (controllingPointer != null && controllingPointer.interactWithObjects && objectInteractor != null && objectInteractor.activeInHierarchy)
|
|
{
|
|
UpdateObjectInteractor();
|
|
}
|
|
|
|
if (pointerOriginTransformFollow != null)
|
|
{
|
|
UpdatePointerOriginTransformFollow();
|
|
}
|
|
}
|
|
|
|
protected virtual void ToggleObjectInteraction(bool state)
|
|
{
|
|
if (controllingPointer != null && controllingPointer.interactWithObjects)
|
|
{
|
|
if (state && controllingPointer.grabToPointerTip && controllerGrabScript != null && objectInteractorAttachPoint != null)
|
|
{
|
|
savedAttachPoint = controllerGrabScript.controllerAttachPoint;
|
|
controllerGrabScript.controllerAttachPoint = objectInteractorAttachPoint.GetComponent<Rigidbody>();
|
|
attachedToInteractorAttachPoint = true;
|
|
}
|
|
|
|
if (!state && controllingPointer.grabToPointerTip && controllerGrabScript != null)
|
|
{
|
|
if (attachedToInteractorAttachPoint)
|
|
{
|
|
controllerGrabScript.ForceRelease(true);
|
|
}
|
|
|
|
if (savedAttachPoint != null)
|
|
{
|
|
controllerGrabScript.controllerAttachPoint = savedAttachPoint;
|
|
savedAttachPoint = null;
|
|
}
|
|
attachedToInteractorAttachPoint = false;
|
|
savedBeamLength = 0f;
|
|
}
|
|
|
|
if (objectInteractor != null)
|
|
{
|
|
objectInteractor.SetActive(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void UpdateObjectInteractor()
|
|
{
|
|
objectInteractor.transform.position = destinationHit.point;
|
|
}
|
|
|
|
protected virtual VRTK_ControllerReference GetControllerReference(GameObject reference = null)
|
|
{
|
|
reference = (reference == null && controllingPointer != null && controllingPointer.controllerEvents != null ? controllingPointer.controllerEvents.gameObject : reference);
|
|
return VRTK_ControllerReference.GetControllerReference(reference);
|
|
}
|
|
|
|
protected virtual Transform GetPointerOriginTransform()
|
|
{
|
|
VRTK_ControllerReference controllerReference = GetControllerReference((controllingPointer != null ? controllingPointer.attachedTo : null));
|
|
if (VRTK_ControllerReference.IsValid(controllerReference) && (cachedAttachedHand != controllerReference.hand || cachedPointerAttachPoint == null))
|
|
{
|
|
cachedPointerAttachPoint = controllerReference.model.transform.Find(VRTK_SDK_Bridge.GetControllerElementPath(SDK_BaseController.ControllerElements.AttachPoint, controllerReference.hand));
|
|
cachedAttachedHand = controllerReference.hand;
|
|
pointerOriginTransformFollow.gameObject.SetActive(false);
|
|
}
|
|
return (cachedPointerAttachPoint != null ? cachedPointerAttachPoint : transform);
|
|
}
|
|
|
|
protected virtual void UpdatePointerOriginTransformFollow()
|
|
{
|
|
pointerOriginTransformFollow.gameObject.SetActive((controllingPointer != null));
|
|
if (controllingPointer != null)
|
|
{
|
|
pointerOriginTransformFollow.gameObjectToFollow = (controllingPointer.customOrigin == null ? GetPointerOriginTransform() : controllingPointer.customOrigin).gameObject;
|
|
pointerOriginTransformFollow.enabled = controllingPointer != null;
|
|
pointerOriginTransformFollowGameObject.SetActive(controllingPointer != null);
|
|
|
|
pointerOriginTransformFollow.smoothsPosition = pointerOriginSmoothingSettings.smoothsPosition;
|
|
pointerOriginTransformFollow.maxAllowedPerFrameDistanceDifference = pointerOriginSmoothingSettings.maxAllowedPerFrameDistanceDifference;
|
|
pointerOriginTransformFollow.smoothsRotation = pointerOriginSmoothingSettings.smoothsRotation;
|
|
pointerOriginTransformFollow.maxAllowedPerFrameAngleDifference = pointerOriginSmoothingSettings.maxAllowedPerFrameAngleDifference;
|
|
}
|
|
}
|
|
|
|
protected Transform GetOrigin(bool smoothed = true)
|
|
{
|
|
return (smoothed ? pointerOriginTransformFollow.gameObjectToChange.transform : (controllingPointer.customOrigin == null ? GetPointerOriginTransform() : controllingPointer.customOrigin));
|
|
}
|
|
|
|
protected virtual void PointerEnter(RaycastHit givenHit)
|
|
{
|
|
controllingPointer.PointerEnter(givenHit);
|
|
}
|
|
|
|
protected virtual void PointerExit(RaycastHit givenHit)
|
|
{
|
|
controllingPointer.PointerExit(givenHit);
|
|
}
|
|
|
|
protected virtual bool ValidDestination()
|
|
{
|
|
bool validNavMeshLocation = false;
|
|
if (navMeshData != null)
|
|
{
|
|
if (destinationHit.transform != null)
|
|
{
|
|
NavMeshHit hit;
|
|
validNavMeshLocation = NavMesh.SamplePosition(destinationHit.point, out hit, navMeshData.distanceLimit, navMeshData.validAreas);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
validNavMeshLocation = true;
|
|
}
|
|
return (validNavMeshLocation && destinationHit.collider != null && !(VRTK_PolicyList.Check(destinationHit.collider.gameObject, invalidListPolicy)));
|
|
}
|
|
|
|
protected virtual void ToggleElement(GameObject givenObject, bool pointerState, bool actualState, VisibilityStates givenVisibility, ref bool currentVisible)
|
|
{
|
|
if (givenObject != null)
|
|
{
|
|
currentVisible = (givenVisibility == VisibilityStates.AlwaysOn ? true : pointerState);
|
|
|
|
givenObject.SetActive(currentVisible);
|
|
|
|
if (givenVisibility == VisibilityStates.AlwaysOff)
|
|
{
|
|
currentVisible = false;
|
|
ToggleRendererVisibility(givenObject, false);
|
|
}
|
|
else
|
|
{
|
|
if (actualState && givenVisibility != VisibilityStates.AlwaysOn)
|
|
{
|
|
ToggleRendererVisibility(givenObject, false);
|
|
AddVisibleRenderer(givenObject);
|
|
}
|
|
else
|
|
{
|
|
ToggleRendererVisibility(givenObject, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void AddVisibleRenderer(GameObject givenObject)
|
|
{
|
|
makeRendererVisible.Add(givenObject);
|
|
}
|
|
|
|
protected virtual void MakeRenderersVisible()
|
|
{
|
|
foreach (GameObject currentRenderer in new HashSet<GameObject>(makeRendererVisible))
|
|
{
|
|
ToggleRendererVisibility(currentRenderer, true);
|
|
}
|
|
makeRendererVisible.Clear();
|
|
}
|
|
|
|
protected virtual void ToggleRendererVisibility(GameObject givenObject, bool state)
|
|
{
|
|
if (givenObject != null)
|
|
{
|
|
Renderer[] renderers = givenObject.GetComponentsInChildren<Renderer>();
|
|
for (int i = 0; i < renderers.Length; i++)
|
|
{
|
|
renderers[i].enabled = state;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void SetupMaterialRenderer(GameObject givenObject)
|
|
{
|
|
if (givenObject != null)
|
|
{
|
|
MeshRenderer pointerRenderer = givenObject.GetComponent<MeshRenderer>();
|
|
pointerRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
pointerRenderer.receiveShadows = false;
|
|
pointerRenderer.material = defaultMaterial;
|
|
}
|
|
}
|
|
|
|
protected virtual void ChangeColor(Color givenColor)
|
|
{
|
|
previousColor = currentColor;
|
|
if ((playareaCursor != null && playareaCursor.IsActive() && playareaCursor.HasCollided()) || !ValidDestination() || (controllingPointer != null && !controllingPointer.CanSelect()))
|
|
{
|
|
givenColor = invalidCollisionColor;
|
|
}
|
|
|
|
if (givenColor != Color.clear)
|
|
{
|
|
currentColor = givenColor;
|
|
ChangeMaterial(givenColor);
|
|
}
|
|
|
|
if (previousColor != currentColor)
|
|
{
|
|
EmitStateEvent();
|
|
}
|
|
}
|
|
|
|
protected virtual void EmitStateEvent()
|
|
{
|
|
if (controllingPointer != null)
|
|
{
|
|
if (IsValidCollision())
|
|
{
|
|
controllingPointer.OnPointerStateValid();
|
|
}
|
|
else
|
|
{
|
|
controllingPointer.OnPointerStateInvalid();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void ChangeMaterial(Color givenColor)
|
|
{
|
|
if (playareaCursor != null)
|
|
{
|
|
playareaCursor.SetMaterialColor(givenColor, IsValidCollision());
|
|
}
|
|
|
|
if (directionIndicator != null)
|
|
{
|
|
directionIndicator.SetMaterialColor(givenColor, IsValidCollision());
|
|
}
|
|
}
|
|
|
|
protected virtual void ChangeMaterialColor(GameObject givenObject, Color givenColor)
|
|
{
|
|
if (givenObject != null)
|
|
{
|
|
Renderer[] foundRenderers = givenObject.GetComponentsInChildren<Renderer>();
|
|
for (int i = 0; i < foundRenderers.Length; i++)
|
|
{
|
|
Renderer foundRenderer = foundRenderers[i];
|
|
if (foundRenderer.material != null)
|
|
{
|
|
foundRenderer.material.EnableKeyword("_EMISSION");
|
|
|
|
if (foundRenderer.material.HasProperty("_Color"))
|
|
{
|
|
foundRenderer.material.color = givenColor;
|
|
}
|
|
|
|
if (foundRenderer.material.HasProperty("_EmissionColor"))
|
|
{
|
|
foundRenderer.material.SetColor("_EmissionColor", VRTK_SharedMethods.ColorDarken(givenColor, 50));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void CreateObjectInteractor()
|
|
{
|
|
objectInteractor = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "BasePointerRenderer_ObjectInteractor_Container"));
|
|
objectInteractor.transform.SetParent(controllingPointer.controllerEvents.transform);
|
|
objectInteractor.transform.localPosition = Vector3.zero;
|
|
objectInteractor.layer = LayerMask.NameToLayer("Ignore Raycast");
|
|
VRTK_PlayerObject.SetPlayerObject(objectInteractor, VRTK_PlayerObject.ObjectTypes.Pointer);
|
|
|
|
GameObject objectInteractorCollider = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "BasePointerRenderer_ObjectInteractor_Collider"));
|
|
objectInteractorCollider.transform.SetParent(objectInteractor.transform);
|
|
objectInteractorCollider.transform.localPosition = Vector3.zero;
|
|
objectInteractorCollider.layer = LayerMask.NameToLayer("Ignore Raycast");
|
|
SphereCollider tmpCollider = objectInteractorCollider.AddComponent<SphereCollider>();
|
|
tmpCollider.isTrigger = true;
|
|
VRTK_PlayerObject.SetPlayerObject(objectInteractorCollider, VRTK_PlayerObject.ObjectTypes.Pointer);
|
|
|
|
if (controllingPointer.grabToPointerTip)
|
|
{
|
|
objectInteractorAttachPoint = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "BasePointerRenderer_ObjectInteractor_AttachPoint"));
|
|
objectInteractorAttachPoint.transform.SetParent(objectInteractor.transform);
|
|
objectInteractorAttachPoint.transform.localPosition = Vector3.zero;
|
|
objectInteractorAttachPoint.layer = LayerMask.NameToLayer("Ignore Raycast");
|
|
Rigidbody objectInteratorRigidBody = objectInteractorAttachPoint.AddComponent<Rigidbody>();
|
|
objectInteratorRigidBody.isKinematic = true;
|
|
objectInteratorRigidBody.freezeRotation = true;
|
|
#if UNITY_2018_3_OR_NEWER
|
|
objectInteratorRigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
|
|
#else
|
|
objectInteratorRigidBody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
|
|
#endif
|
|
VRTK_PlayerObject.SetPlayerObject(objectInteractorAttachPoint, VRTK_PlayerObject.ObjectTypes.Pointer);
|
|
}
|
|
|
|
ScaleObjectInteractor(Vector3.one);
|
|
objectInteractor.SetActive(false);
|
|
}
|
|
|
|
protected virtual void ScaleObjectInteractor(Vector3 scaleAmount)
|
|
{
|
|
if (objectInteractor != null)
|
|
{
|
|
VRTK_SharedMethods.SetGlobalScale(objectInteractor.transform, scaleAmount);
|
|
}
|
|
}
|
|
|
|
protected virtual void CreatePointerOriginTransformFollow()
|
|
{
|
|
pointerOriginTransformFollowGameObject = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "BasePointerRenderer_Origin_Smoothed"));
|
|
pointerOriginTransformFollow = pointerOriginTransformFollowGameObject.AddComponent<VRTK_TransformFollow>();
|
|
pointerOriginTransformFollow.enabled = false;
|
|
pointerOriginTransformFollow.moment = VRTK_TransformFollow.FollowMoment.OnFixedUpdate;
|
|
pointerOriginTransformFollow.followsScale = false;
|
|
}
|
|
|
|
protected virtual void DestroyPointerOriginTransformFollow()
|
|
{
|
|
if (pointerOriginTransformFollowGameObject != null)
|
|
{
|
|
Destroy(pointerOriginTransformFollowGameObject);
|
|
pointerOriginTransformFollowGameObject = null;
|
|
pointerOriginTransformFollow = null;
|
|
}
|
|
}
|
|
|
|
protected virtual float OverrideBeamLength(float currentLength)
|
|
{
|
|
if (controllerGrabScript == null || !controllerGrabScript.GetGrabbedObject())
|
|
{
|
|
savedBeamLength = 0f;
|
|
}
|
|
|
|
if (controllingPointer != null && controllingPointer.interactWithObjects && controllingPointer.grabToPointerTip && attachedToInteractorAttachPoint && controllerGrabScript != null && controllerGrabScript.GetGrabbedObject())
|
|
{
|
|
savedBeamLength = (savedBeamLength == 0f ? currentLength : savedBeamLength);
|
|
return savedBeamLength;
|
|
}
|
|
return currentLength;
|
|
}
|
|
|
|
protected virtual void UpdateDependencies(Vector3 location)
|
|
{
|
|
if (playareaCursor != null)
|
|
{
|
|
playareaCursor.SetPlayAreaCursorTransform(location);
|
|
}
|
|
}
|
|
|
|
protected virtual void SetupDirectionIndicator()
|
|
{
|
|
if (directionIndicator != null && controllingPointer != null && controllingPointer.controllerEvents != null)
|
|
{
|
|
directionIndicator.Initialize(controllingPointer.controllerEvents);
|
|
}
|
|
}
|
|
|
|
protected virtual void UpdateDirectionIndicator()
|
|
{
|
|
RaycastHit destinationHit = GetDestinationHit();
|
|
directionIndicator.SetPosition((ShowDirectionIndicator() && destinationHit.collider != null), destinationHit.point);
|
|
}
|
|
|
|
protected virtual bool ShowDirectionIndicator()
|
|
{
|
|
switch (directionIndicator.indicatorVisibility)
|
|
{
|
|
case VRTK_PointerDirectionIndicator.VisibilityState.OnWhenPointerActive:
|
|
return controllingPointer.IsPointerActive();
|
|
case VRTK_PointerDirectionIndicator.VisibilityState.AlwaysOnWithPointerCursor:
|
|
return (IsCursorVisible() || controllingPointer.IsPointerActive());
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|