diff --git a/Assets~/StandardAssets/Interactors/LineInteractorVisualizer.prefab b/Assets~/StandardAssets/Interactors/LineInteractorVisualizer.prefab
index 06399c6f..5e9bddb8 100644
--- a/Assets~/StandardAssets/Interactors/LineInteractorVisualizer.prefab
+++ b/Assets~/StandardAssets/Interactors/LineInteractorVisualizer.prefab
@@ -47,6 +47,68 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: a0c2a07ed1df1094ba9ac469febef61e, type: 3}
m_Name:
m_EditorClassIdentifier:
+ lineBase: {fileID: 4233110557611249510}
+ defaultLineColor:
+ serializedVersion: 2
+ key0: {r: 1, g: 1, b: 1, a: 1}
+ key1: {r: 1, g: 1, b: 1, a: 1}
+ key2: {r: 0, g: 0, b: 0, a: 0}
+ key3: {r: 0, g: 0, b: 0, a: 0}
+ key4: {r: 0, g: 0, b: 0, a: 0}
+ key5: {r: 0, g: 0, b: 0, a: 0}
+ key6: {r: 0, g: 0, b: 0, a: 0}
+ key7: {r: 0, g: 0, b: 0, a: 0}
+ ctime0: 0
+ ctime1: 65535
+ ctime2: 0
+ ctime3: 0
+ ctime4: 0
+ ctime5: 0
+ ctime6: 0
+ ctime7: 0
+ atime0: 0
+ atime1: 65535
+ atime2: 0
+ atime3: 0
+ atime4: 0
+ atime5: 0
+ atime6: 0
+ atime7: 0
+ m_Mode: 0
+ m_ColorSpace: -1
+ m_NumColorKeys: 2
+ m_NumAlphaKeys: 2
+ lineColorInputDown:
+ serializedVersion: 2
+ key0: {r: 0, g: 0.9806142, b: 1, a: 0}
+ key1: {r: 0, g: 0.9806142, b: 1, a: 1}
+ key2: {r: 0, g: 0, b: 0, a: 1}
+ key3: {r: 0, g: 0, b: 0, a: 0}
+ key4: {r: 0, g: 0, b: 0, a: 0}
+ key5: {r: 0, g: 0, b: 0, a: 0}
+ key6: {r: 0, g: 0, b: 0, a: 0}
+ key7: {r: 0, g: 0, b: 0, a: 0}
+ ctime0: 0
+ ctime1: 65535
+ ctime2: 0
+ ctime3: 0
+ ctime4: 0
+ ctime5: 0
+ ctime6: 0
+ ctime7: 0
+ atime0: 0
+ atime1: 3277
+ atime2: 49151
+ atime3: 65535
+ atime4: 0
+ atime5: 0
+ atime6: 0
+ atime7: 0
+ m_Mode: 0
+ m_ColorSpace: -1
+ m_NumColorKeys: 2
+ m_NumAlphaKeys: 4
+ lineCastResolution: 2
--- !u!114 &4233110557611249510
MonoBehaviour:
m_ObjectHideFlags: 0
diff --git a/Runtime/Input/Interactors/BaseControllerInteractor.cs b/Runtime/Input/Interactors/BaseControllerInteractor.cs
index a9446ac9..07791a6f 100644
--- a/Runtime/Input/Interactors/BaseControllerInteractor.cs
+++ b/Runtime/Input/Interactors/BaseControllerInteractor.cs
@@ -94,10 +94,8 @@ public abstract class BaseControllerInteractor : ControllerPoseSynchronizer, ICo
///
protected bool IsSelectPressed { get; set; } = false;
- ///
- /// true, if any is down on this .
- ///
- protected bool IsInputDown => inputDownActions.Count > 0;
+ ///
+ public bool IsInputDown => inputDownActions.Count > 0;
///
/// True if select has been pressed once since this component was enabled
@@ -387,6 +385,11 @@ protected override void Start()
{
base.Start();
SetCursor();
+
+ if (visualizer.IsNotNull())
+ {
+ visualizer.Interactor = this;
+ }
}
///
@@ -422,12 +425,34 @@ protected override void OnDisable()
}
}
+ ///
+ protected override void OnDestroy()
+ {
+ if (visualizer.IsNotNull())
+ {
+ visualizer.gameObject.Destroy();
+ }
+
+ base.OnDestroy();
+ }
+
///
- public virtual void OnPreRaycast() { }
+ public virtual void OnPreRaycast()
+ {
+ if (visualizer.IsNotNull())
+ {
+ visualizer.OnPreRaycast();
+ }
+ }
///
public virtual void OnPostRaycast()
{
+ if (visualizer.IsNotNull())
+ {
+ visualizer.OnPostRaycast();
+ }
+
if (grabAction != InputAction.None)
{
if (IsGrabPressed)
@@ -440,7 +465,6 @@ public virtual void OnPostRaycast()
if (IsSelectPressed)
{
DragHandler(pointerAction);
-
}
}
}
diff --git a/Runtime/Input/Interactors/BaseInteractorVisualizer.cs b/Runtime/Input/Interactors/BaseInteractorVisualizer.cs
index 76dece37..ba954fe7 100644
--- a/Runtime/Input/Interactors/BaseInteractorVisualizer.cs
+++ b/Runtime/Input/Interactors/BaseInteractorVisualizer.cs
@@ -7,6 +7,13 @@ namespace RealityToolkit.Input.Interactors
{
public abstract class BaseInteractorVisualizer : MonoBehaviour, IInteractorVisualizer
{
+ ///
+ public virtual IInteractor Interactor { get; set; }
+ ///
+ public virtual void OnPreRaycast() { }
+
+ ///
+ public virtual void OnPostRaycast() { }
}
}
diff --git a/Runtime/Input/Interactors/FarInteractor.cs b/Runtime/Input/Interactors/FarInteractor.cs
index cd2d1436..7401a97d 100644
--- a/Runtime/Input/Interactors/FarInteractor.cs
+++ b/Runtime/Input/Interactors/FarInteractor.cs
@@ -2,167 +2,45 @@
// Licensed under the MIT License. See LICENSE in the project root for license information.
using RealityToolkit.Definitions.Physics;
-using RealityToolkit.Utilities.Lines.DataProviders;
-using RealityToolkit.Utilities.Lines.Renderers;
using UnityEngine;
-using UnityEngine.Serialization;
namespace RealityToolkit.Input.Interactors
{
///
/// A simple line pointer for drawing lines from the input source origin to the current pointer position.
///
+ [AddComponentMenu("")]
public class FarInteractor : BaseControllerInteractor
{
- [SerializeField]
- private Gradient defaultLineColor = new Gradient();
-
- protected Gradient DefaultLineColor
- {
- get => defaultLineColor;
- set => defaultLineColor = value;
- }
-
- [SerializeField]
- private Gradient lineColorInputDown = new Gradient();
-
- protected Gradient LineColorInputDown
- {
- get => lineColorInputDown;
- set => lineColorInputDown = value;
- }
-
[Range(2, 50)]
[SerializeField]
- [FormerlySerializedAs("LineCastResolution")]
[Tooltip("This setting has a high performance cost. Values above 20 are not recommended.")]
- private int lineCastResolution = 10;
-
- protected int LineCastResolution
- {
- get => lineCastResolution;
- set => lineCastResolution = value;
- }
-
- [SerializeField]
- private BaseLineDataProvider lineBase;
-
- ///
- /// The Line Data Provider driving this pointer.
- ///
- public BaseLineDataProvider LineBase => lineBase;
-
- [SerializeField]
- [Tooltip("If no line renderers are specified, this array will be auto-populated on startup.")]
- private BaseLineRenderer[] lineRenderers;
+ private int lineCastResolution = 2;
///
- /// The current line renderers that this pointer is utilizing.
+ /// The amount of rays to cast.
///
///
- /// If no line renderers are specified, this array will be auto-populated on startup.
+ /// This setting has a high performance cost. Values above 20 are not recommended.
///
- public BaseLineRenderer[] LineRenderers
+ public int LineCastResolution
{
- get => lineRenderers;
- set => lineRenderers = value;
+ get => lineCastResolution;
+ set => lineCastResolution = value;
}
///
public override bool IsFarInteractor => true;
- private void CheckInitialization()
- {
- if (lineBase == null)
- {
- lineBase = GetComponent();
- }
-
- if (lineBase == null)
- {
- Debug.LogError($"No Mixed Reality Line Data Provider found on {gameObject.name}. Did you forget to add a Line Data provider?");
- }
-
- if (lineBase != null && (lineRenderers == null || lineRenderers.Length == 0))
- {
- lineRenderers = lineBase.GetComponentsInChildren();
- }
-
- if (lineRenderers == null || lineRenderers.Length == 0)
- {
- Debug.LogError($"No Mixed Reality Line Renderers found on {gameObject.name}. Did you forget to add a Mixed Reality Line Renderer?");
- }
- }
-
- #region MonoBehaviour Implementation
-
- protected virtual void OnValidate()
- {
- CheckInitialization();
- }
-
- protected override void OnEnable()
- {
- base.OnEnable();
- CheckInitialization();
- }
-
- #endregion MonoBehaviour Implementation
-
- #region IPointer Implementation
-
- ///
public override void OnPreRaycast()
{
- Debug.Assert(lineBase != null);
-
- lineBase.UpdateMatrix();
-
- if (RayStabilizer != null)
- {
- RayStabilizer.UpdateStability(Rays[0].Origin, Rays[0].Direction);
- Rays[0].CopyRay(RayStabilizer.StableRay, Extent);
- }
-
- TryGetPointerPosition(out var pointerPosition);
- TryGetPointerRotation(out var pointerRotation);
-
- // Set our first and last points
- lineBase.FirstPoint = pointerPosition;
-
- if (IsFocusLocked && Result.CurrentTarget != null)
- {
- if (SyncedTarget != null)
- {
- // Now raycast out like nothing happened so we can get an updated pointer position.
- lineBase.LastPoint = pointerPosition + pointerRotation * (Vector3.forward * Extent);
- }
- else
- {
- // Set the line to the locked position.
- lineBase.LastPoint = Result.EndPoint;
- }
- }
- else
- {
- lineBase.LastPoint = pointerPosition + pointerRotation * (Vector3.forward * Extent);
- }
-
// Make sure our array will hold
if (Rays == null || Rays.Length != lineCastResolution)
{
Rays = new RayStep[lineCastResolution];
}
- var stepSize = 1f / Rays.Length;
- var lastPoint = lineBase.GetUnClampedPoint(0f);
-
- for (int i = 0; i < Rays.Length; i++)
- {
- var currentPoint = lineBase.GetUnClampedPoint(stepSize * (i + 1));
- Rays[i].UpdateRayStep(ref lastPoint, ref currentPoint);
- lastPoint = currentPoint;
- }
+ base.OnPreRaycast();
}
///
@@ -170,8 +48,6 @@ public override void OnPostRaycast()
{
if (!IsInteractionEnabled)
{
- lineBase.enabled = false;
-
if (BaseCursor != null)
{
BaseCursor.IsVisible = false;
@@ -180,64 +56,12 @@ public override void OnPostRaycast()
return;
}
- base.OnPostRaycast();
-
- Gradient lineColor;
-
- lineBase.enabled = true;
-
if (BaseCursor != null)
{
BaseCursor.IsVisible = true;
}
- // Used to ensure the line doesn't extend beyond the cursor
- float cursorOffsetWorldLength = BaseCursor?.SurfaceCursorDistance ?? 0f;
-
- // The distance the ray travels through the world before it hits something.
- // Measured in world-units (as opposed to normalized distance).
- var clearWorldLength = (Result?.CurrentTarget != null) ? Result.RayDistance : Extent;
-
- lineColor = IsInputDown ? LineColorInputDown : DefaultLineColor;
-
- int maxClampLineSteps = lineCastResolution;
-
- for (var i = 0; i < lineRenderers.Length; i++)
- {
- var lineRenderer = lineRenderers[i];
- // Renderers are enabled by default if line is enabled
- lineRenderer.enabled = true;
- maxClampLineSteps = Mathf.Max(maxClampLineSteps, lineRenderer.LineStepCount);
- lineRenderer.LineColor = lineColor;
- }
-
- // If focus is locked, we're sticking to the target
- // So don't clamp the world length
- if (IsFocusLocked && Result.CurrentTarget != null)
- {
- if (SyncedTarget != null)
- {
- if (Result.GrabPoint == Vector3.zero)
- {
- LineBase.LastPoint = Result.EndPoint;
- }
- else
- {
- LineBase.LastPoint = Result.GrabPoint;
- }
- }
-
- float cursorOffsetLocalLength = LineBase.GetNormalizedLengthFromWorldLength(cursorOffsetWorldLength);
- LineBase.LineEndClamp = 1 - cursorOffsetLocalLength;
- }
- else
- {
- // Otherwise clamp the line end by the clear distance
- float clearLocalLength = lineBase.GetNormalizedLengthFromWorldLength(clearWorldLength - cursorOffsetWorldLength, maxClampLineSteps);
- lineBase.LineEndClamp = clearLocalLength;
- }
+ base.OnPostRaycast();
}
-
- #endregion IPointer Implementation
}
}
\ No newline at end of file
diff --git a/Runtime/Input/Interactors/GenericPointer.cs b/Runtime/Input/Interactors/GenericPointer.cs
index 448a6473..7f23ef5d 100644
--- a/Runtime/Input/Interactors/GenericPointer.cs
+++ b/Runtime/Input/Interactors/GenericPointer.cs
@@ -63,6 +63,9 @@ public virtual IController Controller
///
public bool IsOverUI { get; } = false;
+ ///
+ public bool IsInputDown { get; private set; }
+
///
public virtual IInputSource InputSource
{
diff --git a/Runtime/Input/Interactors/IInteractor.cs b/Runtime/Input/Interactors/IInteractor.cs
index fbc2ca9b..e7222591 100644
--- a/Runtime/Input/Interactors/IInteractor.cs
+++ b/Runtime/Input/Interactors/IInteractor.cs
@@ -36,6 +36,11 @@ public interface IInteractor : IEqualityComparer
///
bool IsFarInteractor { get; }
+ ///
+ /// true, if any is down on this .
+ ///
+ bool IsInputDown { get; }
+
///
/// This pointer's input source parent.
///
diff --git a/Runtime/Input/Interactors/IInteractorVisualizer.cs b/Runtime/Input/Interactors/IInteractorVisualizer.cs
index d9b31501..d66cd6d5 100644
--- a/Runtime/Input/Interactors/IInteractorVisualizer.cs
+++ b/Runtime/Input/Interactors/IInteractorVisualizer.cs
@@ -5,6 +5,19 @@ namespace RealityToolkit.Input.Interactors
{
public interface IInteractorVisualizer
{
+ ///
+ /// The visualized.
+ ///
+ IInteractor Interactor { get; }
+ ///
+ /// Called before all rays have casted on the .
+ ///
+ void OnPreRaycast();
+
+ ///
+ /// Called after all rays have casted on the .
+ ///
+ void OnPostRaycast();
}
}
diff --git a/Runtime/Input/Interactors/LineInteractorVisualizer.cs b/Runtime/Input/Interactors/LineInteractorVisualizer.cs
index 4131a44d..b53d10fc 100644
--- a/Runtime/Input/Interactors/LineInteractorVisualizer.cs
+++ b/Runtime/Input/Interactors/LineInteractorVisualizer.cs
@@ -1,10 +1,201 @@
// Copyright (c) Reality Collective. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
+using RealityCollective.Utilities.Extensions;
+using RealityToolkit.Utilities.Lines.DataProviders;
+using RealityToolkit.Utilities.Lines.Renderers;
+using UnityEngine;
+
namespace RealityToolkit.Input.Interactors
{
public class LineInteractorVisualizer : BaseInteractorVisualizer
{
+ [SerializeField]
+ private BaseLineDataProvider lineBase = null;
+
+ [SerializeField]
+ [Tooltip("If no line renderers are specified, this array will be auto-populated on startup.")]
+ private BaseLineRenderer[] lineRenderers = null;
+
+ [SerializeField]
+ private Gradient defaultLineColor = new Gradient();
+
+ public Gradient DefaultLineColor
+ {
+ get => defaultLineColor;
+ set => defaultLineColor = value;
+ }
+
+ [SerializeField]
+ private Gradient lineColorInputDown = new Gradient();
+
+ public Gradient LineColorInputDown
+ {
+ get => lineColorInputDown;
+ set => lineColorInputDown = value;
+ }
+
+ private FarInteractor farInteractor;
+ ///
+ public override IInteractor Interactor
+ {
+ get => farInteractor;
+ set
+ {
+ if (value is FarInteractor farInteractor)
+ {
+ this.farInteractor = farInteractor;
+ return;
+ }
+
+ Debug.LogError($"{nameof(LineInteractorVisualizer)} is only meant to be used with {nameof(FarInteractor)}s.");
+ }
+ }
+
+ protected virtual void OnValidate()
+ {
+ CheckInitialization();
+ }
+
+ protected virtual void OnEnable()
+ {
+ CheckInitialization();
+ }
+
+ private void CheckInitialization()
+ {
+ if (lineBase.IsNull())
+ {
+ lineBase = GetComponent();
+ }
+
+ if (lineBase.IsNull())
+ {
+ Debug.LogError($"No {nameof(BaseLineDataProvider)} found on {gameObject.name}.");
+ }
+
+ if (lineBase.IsNotNull() && (lineRenderers == null || lineRenderers.Length == 0))
+ {
+ lineRenderers = lineBase.GetComponentsInChildren();
+ }
+
+ if (lineRenderers == null || lineRenderers.Length == 0)
+ {
+ Debug.LogError($"No {nameof(BaseLineRenderer)}s found on {gameObject.name}.");
+ }
+ }
+
+ ///
+ public override void OnPreRaycast()
+ {
+ Debug.Assert(lineBase.IsNotNull());
+
+ lineBase.UpdateMatrix();
+
+ if (Interactor == null || !Interactor.IsInteractionEnabled)
+ {
+ lineBase.enabled = false;
+ return;
+ }
+
+ if (Interactor.RayStabilizer != null)
+ {
+ Interactor.RayStabilizer.UpdateStability(Interactor.Rays[0].Origin, Interactor.Rays[0].Direction);
+ Interactor.Rays[0].CopyRay(Interactor.RayStabilizer.StableRay, Interactor.Extent);
+ }
+
+ Interactor.TryGetPointerPosition(out var pointerPosition);
+ Interactor.TryGetPointerRotation(out var pointerRotation);
+
+ // Set our first and last points
+ lineBase.FirstPoint = pointerPosition;
+
+ if (Interactor.IsFocusLocked && Interactor.Result.CurrentTarget != null)
+ {
+ if (Interactor.SyncedTarget != null)
+ {
+ // Now raycast out like nothing happened so we can get an updated pointer position.
+ lineBase.LastPoint = pointerPosition + pointerRotation * (Vector3.forward * Interactor.Extent);
+ }
+ else
+ {
+ // Set the line to the locked position.
+ lineBase.LastPoint = Interactor.Result.EndPoint;
+ }
+ }
+ else
+ {
+ lineBase.LastPoint = pointerPosition + pointerRotation * (Vector3.forward * Interactor.Extent);
+ }
+
+ var stepSize = 1f / Interactor.Rays.Length;
+ var lastPoint = lineBase.GetUnClampedPoint(0f);
+
+ for (int i = 0; i < Interactor.Rays.Length; i++)
+ {
+ var currentPoint = lineBase.GetUnClampedPoint(stepSize * (i + 1));
+ Interactor.Rays[i].UpdateRayStep(ref lastPoint, ref currentPoint);
+ lastPoint = currentPoint;
+ }
+ }
+
+ ///
+ public override void OnPostRaycast()
+ {
+ if (!Interactor.IsInteractionEnabled)
+ {
+ lineBase.enabled = false;
+ return;
+ }
+
+ lineBase.enabled = true;
+
+ Gradient lineColor;
+
+ lineColor = Interactor.IsInputDown ? LineColorInputDown : DefaultLineColor;
+ var maxClampLineSteps = farInteractor.LineCastResolution;
+
+ // Used to ensure the line doesn't extend beyond the cursor
+ float cursorOffsetWorldLength = Interactor.BaseCursor?.SurfaceCursorDistance ?? 0f;
+
+ // The distance the ray travels through the world before it hits something.
+ // Measured in world-units (as opposed to normalized distance).
+ var clearWorldLength = (Interactor.Result?.CurrentTarget != null) ? Interactor.Result.RayDistance : Interactor.Extent;
+
+ for (var i = 0; i < lineRenderers.Length; i++)
+ {
+ var lineRenderer = lineRenderers[i];
+ // Renderers are enabled by default if line is enabled
+ lineRenderer.enabled = true;
+ maxClampLineSteps = Mathf.Max(maxClampLineSteps, lineRenderer.LineStepCount);
+ lineRenderer.LineColor = lineColor;
+ }
+
+ // If focus is locked, we're sticking to the target
+ // So don't clamp the world length
+ if (Interactor.IsFocusLocked && Interactor.Result.CurrentTarget != null)
+ {
+ if (Interactor.SyncedTarget != null)
+ {
+ if (Interactor.Result.GrabPoint == Vector3.zero)
+ {
+ lineBase.LastPoint = Interactor.Result.EndPoint;
+ }
+ else
+ {
+ lineBase.LastPoint = Interactor.Result.GrabPoint;
+ }
+ }
+ var cursorOffsetLocalLength = lineBase.GetNormalizedLengthFromWorldLength(cursorOffsetWorldLength);
+ lineBase.LineEndClamp = 1 - cursorOffsetLocalLength;
+ }
+ else
+ {
+ // Otherwise clamp the line end by the clear distance
+ float clearLocalLength = lineBase.GetNormalizedLengthFromWorldLength(clearWorldLength - cursorOffsetWorldLength, maxClampLineSteps);
+ lineBase.LineEndClamp = clearLocalLength;
+ }
+ }
}
}
diff --git a/Runtime/Utilities/Lines/Modules/BaseLineDataProvider.cs b/Runtime/Utilities/Lines/Modules/BaseLineDataProvider.cs
index 61422f73..9a407931 100644
--- a/Runtime/Utilities/Lines/Modules/BaseLineDataProvider.cs
+++ b/Runtime/Utilities/Lines/Modules/BaseLineDataProvider.cs
@@ -1,6 +1,7 @@
// Copyright (c) Reality Collective. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
+using RealityCollective.Utilities.Extensions;
using RealityToolkit.Definitions.Lines;
using RealityToolkit.Utilities.Physics.Distorters;
using System.Collections.Generic;
@@ -60,7 +61,7 @@ public float LineEndClamp
///
public Transform LineTransform
{
- get => customLineTransform != null ? customLineTransform : transform;
+ get => customLineTransform.IsNotNull() ? customLineTransform : transform;
set => customLineTransform = value;
}