Initial commit
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VRTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws a bezier curve from a starting point transform to an end point transform
|
||||
/// </summary>
|
||||
public class BezierCurve : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// If the view scale changes more than this amount, then the line width will be updated causing the line to be rebuilt.
|
||||
/// </summary>
|
||||
const float k_ViewerScaleChangeThreshold = 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// The time within the frame that the curve will be updated.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.XR.Interaction.Toolkit.XRBaseController.UpdateType"/>
|
||||
public enum UpdateType
|
||||
{
|
||||
/// <summary>
|
||||
/// Sample at both update and directly before rendering. For smooth tracking,
|
||||
/// we recommend using this value as it will provide the lowest input latency for the device.
|
||||
/// </summary>
|
||||
UpdateAndBeforeRender,
|
||||
|
||||
/// <summary>
|
||||
/// Only sample input during the update phase of the frame.
|
||||
/// </summary>
|
||||
Update,
|
||||
|
||||
/// <summary>
|
||||
/// Only sample input directly before rendering.
|
||||
/// </summary>
|
||||
BeforeRender,
|
||||
}
|
||||
|
||||
#pragma warning disable 649
|
||||
[SerializeField, Tooltip("The time within the frame that the curve will be updated. If this Bezier Curve is attached to a transform that is updating before render, then enabling updates in Before Render will keep the line connected without delay.")]
|
||||
UpdateType m_UpdateTrackingType = UpdateType.Update;
|
||||
|
||||
[SerializeField, Tooltip("The transform that determines the position, handle rotation, and handle scale of the start point of the bezier curve.")]
|
||||
Transform m_StartPoint;
|
||||
|
||||
[SerializeField, Tooltip("The transform that determines the position, handle rotation, and handle scale of the end point of the bezier curve.")]
|
||||
Transform m_EndPoint;
|
||||
|
||||
[SerializeField, Tooltip("Controls the scale factor of the curve's start bezier handle.")]
|
||||
float m_CurveFactorStart = 1.0f;
|
||||
|
||||
[SerializeField, Tooltip("Controls the scale factor of the curve's end bezier handle.")]
|
||||
float m_CurveFactorEnd = 1.0f;
|
||||
|
||||
[SerializeField, Tooltip("Controls the number of segments used to draw the curve.")]
|
||||
int m_SegmentCount = 50;
|
||||
|
||||
[SerializeField, Tooltip("When enabled, the line color gradient will be animated so that an opaque part travels along the line.")]
|
||||
bool m_Animate;
|
||||
|
||||
[SerializeField, Tooltip("If animated, this controls the speed that the animation of the line.")]
|
||||
float m_AnimSpeed = 0.25f;
|
||||
|
||||
[SerializeField, Tooltip("If animated, this color will be the main opaque color of the gradient")]
|
||||
Color m_GradientKeyColor = new Color(0.1254902f, 0.5882353f, 0.9529412f);
|
||||
|
||||
[SerializeField, Tooltip("The line renderer that will draw the curve. If not set it will find a line renderer on this GameObject.")]
|
||||
LineRenderer m_LineRenderer;
|
||||
#pragma warning restore 649
|
||||
|
||||
Vector3[] m_ControlPoints = new Vector3[4];
|
||||
float m_Time;
|
||||
float m_LineWidth;
|
||||
float m_LastViewerScale;
|
||||
|
||||
Vector3 m_LastStartPosition;
|
||||
Vector3 m_LastEndPosition;
|
||||
//IProvidesViewerScale IFunctionalitySubscriber<IProvidesViewerScale>.provider { get; set; }
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (m_LineRenderer == null)
|
||||
m_LineRenderer = GetComponent<LineRenderer>();
|
||||
|
||||
m_LineWidth = m_LineRenderer.startWidth;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
DrawCurve();
|
||||
Application.onBeforeRender += OnBeforeRender;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
Application.onBeforeRender -= OnBeforeRender;
|
||||
|
||||
}
|
||||
|
||||
void OnBeforeRender()
|
||||
{
|
||||
if (m_UpdateTrackingType == UpdateType.BeforeRender || m_UpdateTrackingType == UpdateType.UpdateAndBeforeRender)
|
||||
DrawCurve();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (m_UpdateTrackingType == UpdateType.Update || m_UpdateTrackingType == UpdateType.UpdateAndBeforeRender)
|
||||
DrawCurve();
|
||||
|
||||
if (m_Animate)
|
||||
{
|
||||
AnimateCurve();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the line points to draw the bezier curve.
|
||||
/// </summary>
|
||||
[ContextMenu("Draw")]
|
||||
public void DrawCurve()
|
||||
{
|
||||
var startPointPosition = m_StartPoint.position;
|
||||
var endPointPosition = m_EndPoint.position;
|
||||
|
||||
if (startPointPosition == m_LastStartPosition &&
|
||||
endPointPosition == m_LastEndPosition)
|
||||
return; // Return early if the start and end have not changed to avoid recalculating the curve
|
||||
|
||||
var dist = Vector3.Distance(startPointPosition, endPointPosition);
|
||||
|
||||
m_ControlPoints[0] = startPointPosition;
|
||||
m_ControlPoints[1] = startPointPosition + (m_StartPoint.right * (dist * m_CurveFactorStart));
|
||||
m_ControlPoints[2] = endPointPosition - (m_EndPoint.right * (dist * m_CurveFactorEnd));
|
||||
m_ControlPoints[3] = endPointPosition;
|
||||
|
||||
int segmentCount;
|
||||
const float smallestCurveLength = 0.0125f;
|
||||
if (Vector3.Distance(startPointPosition, endPointPosition) < (smallestCurveLength * m_LastViewerScale))
|
||||
{
|
||||
segmentCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
segmentCount = m_SegmentCount;
|
||||
}
|
||||
|
||||
m_LineRenderer.positionCount = segmentCount + 1;
|
||||
m_LineRenderer.SetPosition(0, m_ControlPoints[0]);
|
||||
for (var i = 1; i <= segmentCount; i++)
|
||||
{
|
||||
var t = i / (float)segmentCount;
|
||||
var pixel = CalculateCubicBezierPoint(t, m_ControlPoints[0], m_ControlPoints[1], m_ControlPoints[2], m_ControlPoints[3]);
|
||||
m_LineRenderer.SetPosition(i, pixel);
|
||||
}
|
||||
|
||||
m_LastStartPosition = startPointPosition;
|
||||
m_LastEndPosition = endPointPosition;
|
||||
}
|
||||
|
||||
static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||
{
|
||||
var u = 1 - t;
|
||||
var tt = t * t;
|
||||
var uu = u * u;
|
||||
var uuu = uu * u;
|
||||
var ttt = tt * t;
|
||||
|
||||
var p = uuu * p0;
|
||||
p += 3 * uu * t * p1;
|
||||
p += 3 * u * tt * p2;
|
||||
p += ttt * p3;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void AnimateCurve()
|
||||
{
|
||||
var newGrad = new Gradient();
|
||||
|
||||
var colorKeys = new GradientColorKey[1];
|
||||
var alphaKeys = new GradientAlphaKey[2];
|
||||
|
||||
var colorKey = new GradientColorKey(m_GradientKeyColor, 0f);
|
||||
colorKeys[0] = colorKey;
|
||||
|
||||
var alphaKeyStart = new GradientAlphaKey(.25f, m_Time);
|
||||
var alphaKeyEnd = new GradientAlphaKey(1f, 1f);
|
||||
alphaKeys[0] = alphaKeyStart;
|
||||
alphaKeys[1] = alphaKeyEnd;
|
||||
|
||||
newGrad.SetKeys(colorKeys, alphaKeys);
|
||||
newGrad.mode = GradientMode.Blend;
|
||||
|
||||
m_LineRenderer.colorGradient = newGrad;
|
||||
m_Time += (Time.unscaledDeltaTime * m_AnimSpeed);
|
||||
|
||||
if (m_Time >= 1f)
|
||||
m_Time = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72fb4b8d89bc26347a49177acaa93913
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,129 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VRTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// Callout used to display information like world and controller tooltips.
|
||||
/// </summary>
|
||||
public class Callout : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Tooltip("Whether Gaze Callout is used.")]
|
||||
bool m_UseGazeCallout = true;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The tooltip Transform associated with this Callout.")]
|
||||
Transform m_LazyTooltip;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The line curve GameObject associated with this Callout.")]
|
||||
GameObject m_Curve;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("The required time to dwell on this callout before the tooltip and curve are enabled.")]
|
||||
float m_DwellTime = 1f;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Whether the associated tooltip will be unparented on Start.")]
|
||||
bool m_Unparent = true;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Whether the associated tooltip and curve will be disabled on Start.")]
|
||||
bool m_TurnOffAtStart = true;
|
||||
|
||||
bool m_Gazing = false;
|
||||
|
||||
Coroutine m_StartCo;
|
||||
Coroutine m_EndCo;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (!m_UseGazeCallout)
|
||||
{
|
||||
DisableCallout();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Unparent)
|
||||
{
|
||||
if (m_LazyTooltip != null)
|
||||
m_LazyTooltip.SetParent(null);
|
||||
}
|
||||
|
||||
if (m_TurnOffAtStart)
|
||||
{
|
||||
if (m_LazyTooltip != null)
|
||||
m_LazyTooltip.gameObject.SetActive(false);
|
||||
if (m_Curve != null)
|
||||
m_Curve.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void GazeHoverStart()
|
||||
{
|
||||
if (!m_UseGazeCallout)
|
||||
{
|
||||
DisableCallout();
|
||||
return;
|
||||
}
|
||||
|
||||
m_Gazing = true;
|
||||
if (m_StartCo != null)
|
||||
StopCoroutine(m_StartCo);
|
||||
if (m_EndCo != null)
|
||||
StopCoroutine(m_EndCo);
|
||||
m_StartCo = StartCoroutine(StartDelay());
|
||||
}
|
||||
|
||||
public void GazeHoverEnd()
|
||||
{
|
||||
if (!m_UseGazeCallout)
|
||||
{
|
||||
DisableCallout();
|
||||
return;
|
||||
}
|
||||
|
||||
m_Gazing = false;
|
||||
m_EndCo = StartCoroutine(EndDelay());
|
||||
}
|
||||
|
||||
IEnumerator StartDelay()
|
||||
{
|
||||
yield return new WaitForSeconds(m_DwellTime);
|
||||
if (m_Gazing)
|
||||
TurnOnStuff();
|
||||
}
|
||||
|
||||
IEnumerator EndDelay()
|
||||
{
|
||||
if (!m_Gazing)
|
||||
TurnOffStuff();
|
||||
yield return null;
|
||||
}
|
||||
|
||||
void TurnOnStuff()
|
||||
{
|
||||
if (m_LazyTooltip != null)
|
||||
m_LazyTooltip.gameObject.SetActive(true);
|
||||
if (m_Curve != null)
|
||||
m_Curve.SetActive(true);
|
||||
}
|
||||
|
||||
void TurnOffStuff()
|
||||
{
|
||||
if (m_LazyTooltip != null)
|
||||
m_LazyTooltip.gameObject.SetActive(false);
|
||||
if (m_Curve != null)
|
||||
m_Curve.SetActive(false);
|
||||
}
|
||||
|
||||
void DisableCallout()
|
||||
{
|
||||
if (m_StartCo != null)
|
||||
StopCoroutine(m_StartCo);
|
||||
if (m_EndCo != null)
|
||||
StopCoroutine(m_EndCo);
|
||||
TurnOffStuff();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16809ed3baa3d2341b75ec4c0aa874d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VRTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes this object face a target smoothly and along specific axes
|
||||
/// </summary>
|
||||
public class TurnToFace : MonoBehaviour
|
||||
{
|
||||
#pragma warning disable 649
|
||||
public Transform faceTarget
|
||||
{
|
||||
get => m_FaceTarget;
|
||||
set => m_FaceTarget = value;
|
||||
}
|
||||
[SerializeField]
|
||||
[Tooltip("Target to face towards. If not set, this will default to the main camera")]
|
||||
Transform m_FaceTarget;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Speed to turn")]
|
||||
float m_TurnToFaceSpeed = 5f;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("Local rotation offset")]
|
||||
Vector3 m_RotationOffset = Vector3.zero;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("If enabled, ignore the x axis when rotating")]
|
||||
bool m_IgnoreX;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("If enabled, ignore the y axis when rotating")]
|
||||
bool m_IgnoreY;
|
||||
|
||||
[SerializeField]
|
||||
[Tooltip("If enabled, ignore the z axis when rotating")]
|
||||
bool m_IgnoreZ;
|
||||
#pragma warning restore 649
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Default to main camera
|
||||
if (m_FaceTarget == null)
|
||||
if (Camera.main != null)
|
||||
m_FaceTarget = Camera.main.transform;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (m_FaceTarget != null)
|
||||
{
|
||||
var facePosition = m_FaceTarget.position;
|
||||
var forward = facePosition - transform.position;
|
||||
var targetRotation = forward.sqrMagnitude > float.Epsilon ? Quaternion.LookRotation(forward, Vector3.up) : Quaternion.identity;
|
||||
targetRotation *= Quaternion.Euler(m_RotationOffset);
|
||||
if (m_IgnoreX || m_IgnoreY || m_IgnoreZ)
|
||||
{
|
||||
var targetEuler = targetRotation.eulerAngles;
|
||||
var currentEuler = transform.rotation.eulerAngles;
|
||||
targetRotation = Quaternion.Euler
|
||||
(
|
||||
m_IgnoreX ? currentEuler.x : targetEuler.x,
|
||||
m_IgnoreY ? currentEuler.y : targetEuler.y,
|
||||
m_IgnoreZ ? currentEuler.z : targetEuler.z
|
||||
);
|
||||
}
|
||||
|
||||
var ease = 1f - Mathf.Exp(-m_TurnToFaceSpeed * Time.unscaledDeltaTime);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, ease);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35c58493ec2a8cb43ba320ce1af1adc6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user