Add ultimate xr
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="ArmoredDoor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.CameraUtils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Examples.FullScene.Doors
|
||||
{
|
||||
/// <summary>
|
||||
/// Component to model an automatic door that can not be opened from the outside unless
|
||||
/// <see cref="AutomaticDoor.OpenDoor" /> is called explicitly.
|
||||
/// </summary>
|
||||
public class ArmoredDoor : AutomaticDoor
|
||||
{
|
||||
#region Protected Overrides AutomaticDoor
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether automatic opening is allowed. Only from the inside and the if avatar is not peeking through geometry.
|
||||
/// </summary>
|
||||
protected override bool IsOpeningAllowed => IsAvatarInside(UxrAvatar.LocalAvatar) && !UxrCameraWallFade.IsAvatarPeekingThroughGeometry(UxrAvatar.LocalAvatar);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the avatar is on the back side of the door.
|
||||
/// </summary>
|
||||
/// <param name="avatar">Avatar to check</param>
|
||||
/// <returns>
|
||||
/// Whether the avatar is on the back side of the door. This means it is behind the plane pointed by the floor
|
||||
/// center and looking towards the negative Z.
|
||||
/// </returns>
|
||||
private bool IsAvatarInside(UxrAvatar avatar)
|
||||
{
|
||||
Plane doorPlane = new Plane(FloorCenter.forward, FloorCenter.position);
|
||||
return !doorPlane.GetSide(avatar.CameraPosition);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f0997d4343ed2b4cb9b90f035e6ab72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="AutomaticDoor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Linq;
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Audio;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core.Components;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Examples.FullScene.Doors
|
||||
{
|
||||
/// <summary>
|
||||
/// Component to model de behavior of a door that opens automatically when the user gets near and closes
|
||||
/// when the user moves away from it.
|
||||
/// </summary>
|
||||
public class AutomaticDoor : UxrComponent
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private Transform _floorCenter;
|
||||
[SerializeField] private Transform _leftDoor;
|
||||
[SerializeField] private Transform _rightDoor;
|
||||
[SerializeField] private Vector3 _leftOpenLocalOffset;
|
||||
[SerializeField] private Vector3 _rightOpenLocalOffset;
|
||||
[SerializeField] private float _openDelaySeconds;
|
||||
[SerializeField] private float _openDurationSeconds = 0.8f;
|
||||
[SerializeField] private float _openDistance = 1.5f;
|
||||
[SerializeField] private float _closeDistance = 2.0f;
|
||||
[SerializeField] private UxrEasing _openEasing = UxrEasing.EaseOutCubic;
|
||||
[SerializeField] private UxrEasing _closeEasing = UxrEasing.EaseInCubic;
|
||||
[SerializeField] private UxrAudioSample _audioOpen;
|
||||
[SerializeField] private UxrAudioSample _audioClose;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value from 0.0 (completely closed) to 1.0 (completely open) telling how open the door currently is.
|
||||
/// </summary>
|
||||
public float OpenValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets if the door is open or opening.
|
||||
/// </summary>
|
||||
public bool IsOpen { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Opens the door. This can be used in child implementations where opening can be disallowed under certain
|
||||
/// conditions. See <see cref="ArmoredDoor" /> for an example.
|
||||
/// </summary>
|
||||
/// <param name="playSound">Whether to play the open sound</param>
|
||||
public void OpenDoor(bool playSound)
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
IsOpen = true;
|
||||
|
||||
if (playSound)
|
||||
{
|
||||
_audioOpen.Play(FloorCenter.position);
|
||||
}
|
||||
|
||||
EndSyncMethod(new object[] { playSound });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the door.
|
||||
/// </summary>
|
||||
/// <param name="playSound">Whether to play the close sound</param>
|
||||
public void CloseDoor(bool playSound)
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
// Over closing distance and door completely open: close door
|
||||
IsOpen = false;
|
||||
_openDelayTimer = 0.0f;
|
||||
|
||||
if (playSound)
|
||||
{
|
||||
_audioClose.Play(FloorCenter.position);
|
||||
}
|
||||
|
||||
EndSyncMethod(new object[] { playSound });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Stores initial state.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_leftStartLocalPosition = _leftDoor.localPosition;
|
||||
_rightStartLocalPosition = _rightDoor.localPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the door.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (UxrAvatar.LocalAvatar == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check distance to door
|
||||
|
||||
UxrAvatar closestAvatar = UxrAvatar.EnabledComponents.OrderBy(a => Vector3.Distance(a.CameraFloorPosition, FloorCenter.position)).FirstOrDefault();
|
||||
|
||||
if (closestAvatar == UxrAvatar.LocalAvatar)
|
||||
{
|
||||
// The closest avatar will determine the door state.
|
||||
|
||||
float closestAvatarDistance = Vector3.Distance(closestAvatar.CameraFloorPosition, FloorCenter.position);
|
||||
|
||||
if (closestAvatarDistance < _openDistance && Mathf.Approximately(OpenValue, 0.0f))
|
||||
{
|
||||
_openDelayTimer += Time.deltaTime;
|
||||
|
||||
if (_openDelayTimer > _openDelaySeconds && IsOpeningAllowed)
|
||||
{
|
||||
// Within opening distance, door completely closed and opening allowed: open door
|
||||
OpenDoor(true);
|
||||
}
|
||||
}
|
||||
else if (closestAvatarDistance > _closeDistance && Mathf.Approximately(OpenValue, 1.0f))
|
||||
{
|
||||
CloseDoor(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Update timer and perform interpolation
|
||||
|
||||
OpenValue = Mathf.Clamp01(OpenValue + Time.deltaTime * (1.0f / _openDurationSeconds) * (IsOpen ? 1.0f : -1.0f));
|
||||
float t = UxrInterpolator.GetInterpolationFactor(OpenValue, IsOpen ? _openEasing : _closeEasing);
|
||||
|
||||
_leftDoor.transform.localPosition = Vector3.Lerp(_leftStartLocalPosition, _leftStartLocalPosition + _leftOpenLocalOffset, t);
|
||||
_rightDoor.transform.localPosition = Vector3.Lerp(_rightStartLocalPosition, _rightStartLocalPosition + _rightOpenLocalOffset, t);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets if opening is allowed. Can be used by child implementations to disallow opening under certain conditions. See
|
||||
/// <see cref="ArmoredDoor" /> for an example.
|
||||
/// </summary>
|
||||
protected virtual bool IsOpeningAllowed => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the door center at floor level.
|
||||
/// </summary>
|
||||
protected Transform FloorCenter => _floorCenter != null ? _floorCenter : transform;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private float _openDelayTimer;
|
||||
private Vector3 _leftStartLocalPosition;
|
||||
private Vector3 _rightStartLocalPosition;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dc12cc8ceda632428882a248e42df44
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
347
Assets/UltimateXR/Samples/FullScene/Scripts/Doors/HandScanner.cs
Normal file
347
Assets/UltimateXR/Samples/FullScene/Scripts/Doors/HandScanner.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="HandScanner.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Animation.Materials;
|
||||
using UltimateXR.Audio;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Components;
|
||||
using UltimateXR.Extensions.Unity.Math;
|
||||
using UltimateXR.Extensions.Unity.Render;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Examples.FullScene.Doors
|
||||
{
|
||||
/// <summary>
|
||||
/// Component that handles the hand scanning required to open an <see cref="ArmoredDoor" />.
|
||||
/// </summary>
|
||||
public class HandScanner : UxrComponent
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private ArmoredDoor _armoredDoor;
|
||||
[SerializeField] private Renderer _validLight;
|
||||
[SerializeField] private Renderer _invalidLight;
|
||||
[SerializeField] private Renderer _scannerBeam;
|
||||
[SerializeField] private Vector3 _scannerBeamTopLocalPos;
|
||||
[SerializeField] private Vector3 _scannerBeamBottomLocalPos;
|
||||
[SerializeField] private int _beamCount = 5;
|
||||
[SerializeField] [Range(0.0f, 1.0f)] private float _beamTrailDelay = 0.1f;
|
||||
[SerializeField] private UxrEasing _beamEeasing = UxrEasing.EaseInOutQuint;
|
||||
[SerializeField] private Vector3 _beamMaxScale = Vector3.one;
|
||||
[SerializeField] private Renderer _handRendererLeft;
|
||||
[SerializeField] private Renderer _handRendererRight;
|
||||
[SerializeField] private UxrHandSide _defaultHandSide = UxrHandSide.Right;
|
||||
[SerializeField] private BoxCollider _handBoxValidPos;
|
||||
[SerializeField] private float _scanSeconds = 1.5f;
|
||||
[SerializeField] private float _resultSeconds = 2.0f;
|
||||
[SerializeField] private UxrAudioSample _audioScan;
|
||||
[SerializeField] private UxrAudioSample _audioError;
|
||||
[SerializeField] private UxrAudioSample _audioOk;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Event called right after a hand was scanned. Parameters are the avatar that was scanned and if the scan granted
|
||||
/// access.
|
||||
/// </summary>
|
||||
public event Action<UxrAvatar, UxrHandSide, bool> HandScanned;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
_colorValid = _validLight.sharedMaterial.GetColor(UxrConstants.Shaders.StandardColorVarName);
|
||||
_colorInvalid = _invalidLight.sharedMaterial.GetColor(UxrConstants.Shaders.StandardColorVarName);
|
||||
_handSide = _defaultHandSide;
|
||||
_beamScale = _scannerBeam.transform.localScale;
|
||||
|
||||
_beams.Add(_scannerBeam);
|
||||
|
||||
for (int i = 0; i < _beamCount - 1; ++i)
|
||||
{
|
||||
_beams.Add(Instantiate(_scannerBeam.gameObject, _scannerBeam.transform.position, _scannerBeam.transform.rotation, _scannerBeam.transform.parent).GetComponent<Renderer>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default scanning state.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_scanReady = true;
|
||||
_validLight.enabled = false;
|
||||
_invalidLight.enabled = false;
|
||||
|
||||
_handRendererLeft.enabled = _defaultHandSide == UxrHandSide.Left;
|
||||
_handRendererRight.enabled = _defaultHandSide == UxrHandSide.Right;
|
||||
_handRendererLeft.material.color = ColorExt.ColorAlpha(_handRendererLeft.material.color, _defaultHandSide == UxrHandSide.Left ? 1.0f : 0.0f);
|
||||
_handRendererRight.material.color = ColorExt.ColorAlpha(_handRendererRight.material.color, _defaultHandSide == UxrHandSide.Right ? 1.0f : 0.0f);
|
||||
|
||||
EnableBeams(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the component.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_scanReady = true;
|
||||
_validLight.enabled = false;
|
||||
_invalidLight.enabled = false;
|
||||
EnableBeams(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the component. Performs the scanning process.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (UxrAvatar.LocalAvatar == null || !_scanReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update scanning & beam
|
||||
|
||||
if (_scanTimer < 0.0f)
|
||||
{
|
||||
if (_armoredDoor != null && _armoredDoor.IsOpen)
|
||||
{
|
||||
// If we are controlling an armored door and it is already open, ignore the hands.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Waiting for hand to be scanned. Look for hand:
|
||||
|
||||
if (UxrAvatar.LocalAvatar.GetHandBone(UxrHandSide.Left).position.IsInsideBox(_handBoxValidPos))
|
||||
{
|
||||
StartScan(UxrAvatar.LocalAvatar, UxrHandSide.Left);
|
||||
}
|
||||
else if (UxrAvatar.LocalAvatar.GetHandBone(UxrHandSide.Right).position.IsInsideBox(_handBoxValidPos))
|
||||
{
|
||||
StartScan(UxrAvatar.LocalAvatar, UxrHandSide.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hand is scanning
|
||||
|
||||
_scanTimer += Time.deltaTime;
|
||||
EnableBeams(true);
|
||||
|
||||
for (int i = 0; i < _beams.Count; ++i)
|
||||
{
|
||||
float beamStartTime = i / (_beams.Count == 1 ? 1.0f : _beams.Count - 1.0f) * _beamTrailDelay * _scanSeconds;
|
||||
float beamDuration = _scanSeconds - _beamTrailDelay;
|
||||
float t = Mathf.Clamp01((_scanTimer - beamStartTime) / beamDuration);
|
||||
float tScale = 1.0f - Mathf.Abs(t - 0.5f) * 2.0f;
|
||||
_beams[i].transform.localPosition = Vector3.Lerp(_scannerBeamTopLocalPos, _scannerBeamBottomLocalPos, UxrInterpolator.GetInterpolationFactor(t, _beamEeasing));
|
||||
_beams[i].transform.localScale = Vector3.Lerp(_beamScale, _beamMaxScale, Mathf.Pow(tScale, 8.0f));
|
||||
}
|
||||
|
||||
// Check for conditions
|
||||
|
||||
if (_avatarScanning == UxrAvatar.LocalAvatar)
|
||||
{
|
||||
if (UxrAvatar.LocalAvatar.GetHandBone(_handSide).position.IsInsideBox(_handBoxValidPos))
|
||||
{
|
||||
if (!UxrAvatar.LocalAvatar.GetHandBone(UxrUtils.GetOppositeSide(_handSide)).position.IsInsideBox(_handBoxValidPos))
|
||||
{
|
||||
// Keep scanning
|
||||
|
||||
if (_scanTimer > _scanSeconds)
|
||||
{
|
||||
ProcessScanResult(UxrAvatar.LocalAvatar, _handSide, true);
|
||||
|
||||
if (_armoredDoor != null)
|
||||
{
|
||||
_armoredDoor.OpenDoor(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Opposite hand got in. Aborting.
|
||||
ProcessScanResult(UxrAvatar.LocalAvatar, _handSide, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scanning hand got out. Aborting.
|
||||
ProcessScanResult(UxrAvatar.LocalAvatar, _handSide, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update scan side
|
||||
|
||||
if (_handSide == UxrHandSide.Left)
|
||||
{
|
||||
if (_handRendererRight.enabled)
|
||||
{
|
||||
float rightAlpha = _handRendererRight.material.color.a - Time.deltaTime * HandAlphaSwitchSpeed;
|
||||
_handRendererRight.material.color = ColorExt.ColorAlpha(_handRendererRight.material.color, Mathf.Clamp01(rightAlpha));
|
||||
|
||||
if (rightAlpha < 0.0f)
|
||||
{
|
||||
_handRendererRight.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_handRendererLeft.enabled)
|
||||
{
|
||||
_handRendererLeft.enabled = true;
|
||||
}
|
||||
|
||||
_handRendererLeft.material.color = ColorExt.ColorAlpha(_handRendererLeft.material.color, Mathf.Clamp01(_handRendererLeft.material.color.a + Time.deltaTime * HandAlphaSwitchSpeed));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_handRendererLeft.enabled)
|
||||
{
|
||||
float leftAlpha = _handRendererLeft.material.color.a - Time.deltaTime * HandAlphaSwitchSpeed;
|
||||
_handRendererLeft.material.color = ColorExt.ColorAlpha(_handRendererLeft.material.color, Mathf.Clamp01(leftAlpha));
|
||||
|
||||
if (leftAlpha < 0.0f)
|
||||
{
|
||||
_handRendererLeft.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_handRendererRight.enabled)
|
||||
{
|
||||
_handRendererRight.enabled = true;
|
||||
}
|
||||
|
||||
_handRendererRight.material.color = ColorExt.ColorAlpha(_handRendererRight.material.color, Mathf.Clamp01(_handRendererRight.material.color.a + Time.deltaTime * HandAlphaSwitchSpeed));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Starts scanning a hand.
|
||||
/// </summary>
|
||||
/// <param name="avatarScanning">The avatar that started scanning</param>
|
||||
/// <param name="handSide">The side of the hand being scanned</param>
|
||||
private void StartScan(UxrAvatar avatarScanning, UxrHandSide handSide)
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
_scanTimer = 0.0f;
|
||||
_handSide = handSide;
|
||||
_avatarScanning = avatarScanning;
|
||||
_audioScan.Play(transform.position);
|
||||
|
||||
EndSyncMethod(new object[] { avatarScanning, handSide });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables/disables the scanning beams.
|
||||
/// </summary>
|
||||
/// <param name="enable">Whether the beams should be enabled</param>
|
||||
private void EnableBeams(bool enable)
|
||||
{
|
||||
_beams.ForEach(r => r.enabled = enable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes a scan result.
|
||||
/// </summary>
|
||||
/// <param name="avatar">Avatar that was scanned</param>
|
||||
/// <param name="handSide">Which hand was scanned</param>
|
||||
/// <param name="isValid">Whether the access was granted</param>
|
||||
private void ProcessScanResult(UxrAvatar avatar, UxrHandSide handSide, bool isValid)
|
||||
{
|
||||
BeginSync();
|
||||
|
||||
EnableBeams(false);
|
||||
|
||||
_scanReady = false;
|
||||
_scanTimer = -1.0f;
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
_audioOk.Play(transform.position);
|
||||
_validLight.enabled = true;
|
||||
UxrAnimatedMaterial.AnimateBlinkColor(_validLight.gameObject,
|
||||
UxrConstants.Shaders.StandardColorVarName,
|
||||
_colorValid.WithAlpha(0.0f),
|
||||
_colorValid,
|
||||
UxrAnimatedMaterial.DefaultBlinkFrequency,
|
||||
_resultSeconds,
|
||||
UxrMaterialMode.InstanceOnly,
|
||||
() =>
|
||||
{
|
||||
_scanReady = true;
|
||||
_validLight.enabled = false;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_audioError.Play(transform.position);
|
||||
_invalidLight.enabled = true;
|
||||
UxrAnimatedMaterial.AnimateBlinkColor(_invalidLight.gameObject,
|
||||
UxrConstants.Shaders.StandardColorVarName,
|
||||
_colorInvalid.WithAlpha(0.0f),
|
||||
_colorInvalid,
|
||||
UxrAnimatedMaterial.DefaultBlinkFrequency,
|
||||
_resultSeconds,
|
||||
UxrMaterialMode.InstanceOnly,
|
||||
() =>
|
||||
{
|
||||
_scanReady = true;
|
||||
_invalidLight.enabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
HandScanned?.Invoke(avatar, handSide, isValid);
|
||||
|
||||
EndSyncMethod(new object[] { avatar, handSide, isValid });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Controls how fast the hand image will switch from one side to the other when a different hand than the currently
|
||||
/// shown is placed on the scanner.
|
||||
/// </summary>
|
||||
private const float HandAlphaSwitchSpeed = 4.0f;
|
||||
|
||||
private readonly List<Renderer> _beams = new List<Renderer>();
|
||||
|
||||
private bool _scanReady = true;
|
||||
private float _scanTimer = -1.0f;
|
||||
private Vector3 _beamScale;
|
||||
private UxrAvatar _avatarScanning;
|
||||
private UxrHandSide _handSide;
|
||||
private Color _colorValid;
|
||||
private Color _colorInvalid;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48bb21b6c6a28c64bb55c8b2c38283b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user