184 lines
6.5 KiB
C#
184 lines
6.5 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Microsoft.MixedReality.Toolkit.Utilities
|
|
{
|
|
/// <summary>
|
|
/// Utility component to animate and visualize a light that can be used with
|
|
/// the "MixedRealityToolkit/Standard" shader "_HoverLight" feature.
|
|
/// </summary>
|
|
[ExecuteInEditMode]
|
|
[HelpURL("https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/rendering/hover-light")]
|
|
[AddComponentMenu("Scripts/MRTK/Core/HoverLight")]
|
|
public class HoverLight : MonoBehaviour
|
|
{
|
|
// The MRTK Standard shader supports two (2) hover lights by default, but will scale to support four (4) then ten (10) as
|
|
// more lights are added to the scene. Having many HoverLights illuminate a material will increase pixel shader instructions
|
|
// and will impact performance. Please profile light changes within your project.
|
|
private const int hoverLightCountLow = 2;
|
|
private const int hoverLightCountMedium = 4;
|
|
private const string hoverLightCountMediumName = "_HOVER_LIGHT_MEDIUM";
|
|
private const int hoverLightCountHigh = 10;
|
|
private const string hoverLightCountHighName = "_HOVER_LIGHT_HIGH";
|
|
private const int hoverLightDataSize = 2;
|
|
|
|
private static List<HoverLight> activeHoverLights = new List<HoverLight>(hoverLightCountHigh);
|
|
private static Vector4[] hoverLightData = new Vector4[hoverLightDataSize * hoverLightCountHigh];
|
|
private static int _HoverLightDataID;
|
|
private static int lastHoverLightUpdate = -1;
|
|
|
|
[Tooltip("Specifies the radius of the HoverLight effect")]
|
|
[SerializeField]
|
|
[Range(0.0f, 1.0f)]
|
|
private float radius = 0.15f;
|
|
|
|
/// <summary>
|
|
/// Specifies the Radius of the HoverLight effect
|
|
/// </summary>
|
|
public float Radius
|
|
{
|
|
get => radius;
|
|
set => radius = value;
|
|
}
|
|
|
|
[Tooltip("Specifies the highlight color")]
|
|
[SerializeField]
|
|
private Color color = new Color(0.3f, 0.3f, 0.3f, 1.0f);
|
|
|
|
/// <summary>
|
|
/// Specifies the highlight color
|
|
/// </summary>
|
|
public Color Color
|
|
{
|
|
get => color;
|
|
set => color = value;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
AddHoverLight(this);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
RemoveHoverLight(this);
|
|
UpdateHoverLights(true);
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private void Update()
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Initialize();
|
|
UpdateHoverLights();
|
|
}
|
|
#endif // UNITY_EDITOR
|
|
|
|
private void LateUpdate()
|
|
{
|
|
UpdateHoverLights();
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (!enabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Gizmos.color = Color;
|
|
Gizmos.DrawWireSphere(transform.position, Radius);
|
|
Gizmos.DrawIcon(transform.position + Vector3.right * Radius, string.Empty, false);
|
|
Gizmos.DrawIcon(transform.position + Vector3.left * Radius, string.Empty, false);
|
|
Gizmos.DrawIcon(transform.position + Vector3.up * Radius, string.Empty, false);
|
|
Gizmos.DrawIcon(transform.position + Vector3.down * Radius, string.Empty, false);
|
|
Gizmos.DrawIcon(transform.position + Vector3.forward * Radius, string.Empty, false);
|
|
Gizmos.DrawIcon(transform.position + Vector3.back * Radius, string.Empty, false);
|
|
}
|
|
|
|
private void AddHoverLight(HoverLight light)
|
|
{
|
|
if (activeHoverLights.Count == hoverLightCountLow)
|
|
{
|
|
Shader.EnableKeyword(hoverLightCountMediumName);
|
|
}
|
|
else if (activeHoverLights.Count == hoverLightCountMedium)
|
|
{
|
|
Shader.DisableKeyword(hoverLightCountMediumName);
|
|
Shader.EnableKeyword(hoverLightCountHighName);
|
|
}
|
|
else if (activeHoverLights.Count >= hoverLightCountHigh)
|
|
{
|
|
Debug.LogWarningFormat("Max hover light count {0} exceeded. {1} will not be considered by the MRTK Standard shader.", hoverLightCountHigh, light.gameObject.name);
|
|
}
|
|
|
|
activeHoverLights.Add(light);
|
|
}
|
|
|
|
private void RemoveHoverLight(HoverLight light)
|
|
{
|
|
activeHoverLights.Remove(light);
|
|
|
|
if (activeHoverLights.Count == hoverLightCountLow)
|
|
{
|
|
Shader.DisableKeyword(hoverLightCountMediumName);
|
|
}
|
|
else if (activeHoverLights.Count == hoverLightCountMedium)
|
|
{
|
|
Shader.EnableKeyword(hoverLightCountMediumName);
|
|
Shader.DisableKeyword(hoverLightCountHighName);
|
|
}
|
|
}
|
|
|
|
private void Initialize()
|
|
{
|
|
_HoverLightDataID = Shader.PropertyToID("_HoverLightData");
|
|
}
|
|
|
|
private void UpdateHoverLights(bool forceUpdate = false)
|
|
{
|
|
if (lastHoverLightUpdate == -1)
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
if (!forceUpdate && (Time.frameCount == lastHoverLightUpdate))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < hoverLightCountHigh; ++i)
|
|
{
|
|
HoverLight light = (i >= activeHoverLights.Count) ? null : activeHoverLights[i];
|
|
int dataIndex = i * hoverLightDataSize;
|
|
|
|
if (light)
|
|
{
|
|
hoverLightData[dataIndex] = new Vector4(light.transform.position.x,
|
|
light.transform.position.y,
|
|
light.transform.position.z,
|
|
1.0f);
|
|
hoverLightData[dataIndex + 1] = new Vector4(light.Color.r,
|
|
light.Color.g,
|
|
light.Color.b,
|
|
1.0f / Mathf.Clamp(light.Radius, 0.001f, 1.0f));
|
|
}
|
|
else
|
|
{
|
|
hoverLightData[dataIndex] = Vector4.zero;
|
|
}
|
|
}
|
|
|
|
Shader.SetGlobalVectorArray(_HoverLightDataID, hoverLightData);
|
|
|
|
lastHoverLightUpdate = Time.frameCount;
|
|
}
|
|
}
|
|
} |