mixedreality/com.microsoft.mixedreality..../Core/Utilities/Lines/Renderers/MixedRealityLineRenderer.cs

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;
}
}
}