264 lines
8.5 KiB
C#
264 lines
8.5 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace Microsoft.MixedReality.Toolkit.Utilities
|
|
{
|
|
/// <summary>
|
|
/// Implements Unity's built in line renderer component, and applies the line data to it.
|
|
/// </summary>
|
|
[RequireComponent(typeof(LineRenderer))]
|
|
[AddComponentMenu("Scripts/MRTK/Core/MixedRealityLineRenderer")]
|
|
public class MixedRealityLineRenderer : BaseMixedRealityLineRenderer
|
|
{
|
|
[Header("Mixed Reality Line Renderer Settings")]
|
|
|
|
[SerializeField]
|
|
[Tooltip("The material to use for the Unity MixedRealityLineRenderer.")]
|
|
private Material lineMaterial = null;
|
|
|
|
public Material LineMaterial
|
|
{
|
|
get => lineMaterial;
|
|
set => lineMaterial = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool roundedEdges = true;
|
|
|
|
public bool RoundedEdges
|
|
{
|
|
get => roundedEdges;
|
|
set => roundedEdges = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool roundedCaps = true;
|
|
|
|
public bool RoundedCaps
|
|
{
|
|
get => roundedCaps;
|
|
set => roundedCaps = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
[Tooltip("Sets whether the pointer line will animate to a lower brightness level after a hand/controller is recognized.")]
|
|
private bool fadeLineBrightnessOnEnable = true;
|
|
|
|
/// <summary>
|
|
/// Sets whether the ray line will animate to a lower brightness level on enable of this component
|
|
/// </summary>
|
|
public bool FadeLineBrightnessOnEnable
|
|
{
|
|
get => fadeLineBrightnessOnEnable;
|
|
set => fadeLineBrightnessOnEnable = value;
|
|
}
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
[Tooltip("The amount the pointer line will fade if FadeLineBrightnessOnEnable is true.")]
|
|
private float fadeLinePercentage = 0.55f;
|
|
|
|
/// <summary>
|
|
/// The amount the pointer line will fade if FadeLineBrightnessOnEnable is true"
|
|
/// </summary>
|
|
public float FadeLinePercentage
|
|
{
|
|
get => fadeLinePercentage;
|
|
set => fadeLinePercentage = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
[Tooltip("The length of the animation if fadeLineBrightnessOnEnable is true.")]
|
|
private float fadeLineAnimationTime = 0.65f;
|
|
|
|
/// <summary>
|
|
/// The amount the pointer line will fade if fadeLineBrightnessOnEnable is true"
|
|
/// </summary>
|
|
public float FadeLineAnimationTime
|
|
{
|
|
get => fadeLineAnimationTime;
|
|
set => fadeLineAnimationTime = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the LineRenderer points
|
|
/// </summary>
|
|
public IReadOnlyList<Vector3> Positions => positions;
|
|
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private LineRenderer lineRenderer = null;
|
|
|
|
[Header("Texture Tiling")]
|
|
[SerializeField]
|
|
[Tooltip("Tiles the material on the line renderer by world length. Use if you want the texture size to remain constant regardless of a line's length.")]
|
|
private bool tileMaterialByWorldLength = false;
|
|
private MaterialPropertyBlock tilingPropertyBlock;
|
|
private Vector4 tilingPropertyVector = Vector4.one;
|
|
|
|
[SerializeField]
|
|
private float tileMaterialScale = 1f;
|
|
|
|
private Vector3[] positions;
|
|
|
|
private Coroutine fadeLine = null;
|
|
private GradientAlphaKey[] cachedKeys;
|
|
|
|
private void OnEnable()
|
|
{
|
|
lineRenderer = gameObject.EnsureComponent<LineRenderer>();
|
|
|
|
if (LineMaterial == null)
|
|
{
|
|
LineMaterial = lineRenderer.sharedMaterial;
|
|
}
|
|
|
|
// mafinc - Start the line renderer off disabled (invisible), we'll enable it
|
|
// when we have enough data for it to render properly.
|
|
if (lineRenderer != null)
|
|
{
|
|
lineRenderer.enabled = false;
|
|
}
|
|
|
|
if (LineMaterial == null)
|
|
{
|
|
Debug.LogError("MixedRealityLineRenderer needs a material.");
|
|
enabled = false;
|
|
}
|
|
|
|
if (FadeLineBrightnessOnEnable && Application.isPlaying)
|
|
{
|
|
fadeLine = StartCoroutine(FadeLine(FadeLinePercentage, FadeLineAnimationTime));
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
lineRenderer.enabled = false;
|
|
|
|
if (fadeLine != null)
|
|
{
|
|
StopCoroutine(fadeLine);
|
|
fadeLine = null;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void UpdateLine()
|
|
{
|
|
if (LineDataSource == null)
|
|
{
|
|
enabled = false;
|
|
lineRenderer.enabled = false;
|
|
return;
|
|
}
|
|
|
|
lineRenderer.enabled = lineDataSource.enabled;
|
|
lineRenderer.positionCount = StepMode == StepMode.FromSource ? lineDataSource.PointCount : LineStepCount;
|
|
|
|
if (positions == null || positions.Length != lineRenderer.positionCount)
|
|
{
|
|
positions = new Vector3[lineRenderer.positionCount];
|
|
}
|
|
|
|
for (int i = 0; i < positions.Length; i++)
|
|
{
|
|
if (StepMode == StepMode.FromSource)
|
|
{
|
|
positions[i] = lineDataSource.GetPoint(i);
|
|
}
|
|
else
|
|
{
|
|
float normalizedDistance = GetNormalizedPointAlongLine(i);
|
|
positions[i] = lineDataSource.GetPoint(normalizedDistance);
|
|
}
|
|
}
|
|
|
|
// Set line renderer properties
|
|
lineRenderer.loop = lineDataSource.Loops;
|
|
lineRenderer.numCapVertices = roundedCaps ? 8 : 0;
|
|
lineRenderer.numCornerVertices = roundedEdges ? 8 : 0;
|
|
lineRenderer.useWorldSpace = true;
|
|
lineRenderer.startWidth = 1;
|
|
lineRenderer.endWidth = 1;
|
|
lineRenderer.startColor = Color.white;
|
|
lineRenderer.endColor = Color.white;
|
|
lineRenderer.sharedMaterial = lineMaterial;
|
|
lineRenderer.widthCurve = LineWidth;
|
|
lineRenderer.widthMultiplier = WidthMultiplier;
|
|
lineRenderer.colorGradient = LineColor;
|
|
lineRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
|
lineRenderer.lightProbeUsage = LightProbeUsage.Off;
|
|
|
|
// Set positions
|
|
lineRenderer.positionCount = positions.Length;
|
|
lineRenderer.SetPositions(positions);
|
|
|
|
// Update texture tiling, if applicable
|
|
if (tileMaterialByWorldLength)
|
|
{
|
|
if (tilingPropertyBlock == null)
|
|
{
|
|
tilingPropertyBlock = new MaterialPropertyBlock();
|
|
}
|
|
|
|
tilingPropertyVector.x = lineDataSource.UnClampedWorldLength * tileMaterialScale;
|
|
tilingPropertyBlock.SetVector("_MainTex_ST", tilingPropertyVector);
|
|
lineRenderer.SetPropertyBlock(tilingPropertyBlock);
|
|
}
|
|
else
|
|
{
|
|
if (tilingPropertyBlock != null)
|
|
{
|
|
tilingPropertyBlock.Clear();
|
|
lineRenderer.SetPropertyBlock(tilingPropertyBlock);
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator FadeLine(float targetAlphaPercentage, float animationLength)
|
|
{
|
|
float currentTime = 0f;
|
|
|
|
if (cachedKeys == null)
|
|
{
|
|
cachedKeys = LineColor.alphaKeys;
|
|
}
|
|
|
|
GradientAlphaKey[] fadedKeys = new GradientAlphaKey[cachedKeys.Length];
|
|
Array.Copy(cachedKeys, fadedKeys, cachedKeys.Length);
|
|
float startAlpha = 1f;
|
|
|
|
while (currentTime != animationLength)
|
|
{
|
|
currentTime += Time.deltaTime;
|
|
|
|
if (currentTime > animationLength)
|
|
{
|
|
currentTime = animationLength;
|
|
}
|
|
|
|
float percentageComplete = currentTime / animationLength;
|
|
|
|
float scalar = Mathf.Lerp(startAlpha, targetAlphaPercentage, percentageComplete);
|
|
|
|
for (int i = 0; i < fadedKeys.Length; i++)
|
|
{
|
|
fadedKeys[i].alpha = cachedKeys[i].alpha * scalar;
|
|
}
|
|
|
|
LineColor.alphaKeys = fadedKeys;
|
|
|
|
yield return null;
|
|
}
|
|
|
|
fadeLine = null;
|
|
}
|
|
}
|
|
}
|