Add ultimate xr

This commit is contained in:
2024-08-06 21:58:35 +02:00
parent 864033bf10
commit 7165bacd9d
3952 changed files with 2162037 additions and 35 deletions

View File

@@ -0,0 +1,40 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrCameraDepthEnable.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core.Components.Composite;
using UnityEngine;
namespace UltimateXR.CameraUtils
{
/// <summary>
/// Component added to a camera, enabling camera depth texture mode <see cref="Camera" />. Depth texture mode is
/// required for soft particles.
/// </summary>
public class UxrCameraDepthEnable : UxrAvatarComponent<UxrCameraDepthEnable>
{
#region Inspector Properties/Serialized Fields
[SerializeField] private DepthTextureMode _depthTextureMode = DepthTextureMode.Depth;
#endregion
#region Unity
/// <summary>
/// Called at startup. Sets up the camera with the given parameter.
/// </summary>
protected override void Awake()
{
base.Awake();
if (Avatar.CameraComponent)
{
Avatar.CameraComponent.depthTextureMode = _depthTextureMode;
}
}
#endregion
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0694c9893d18f394c87b81fcf790fd3c
timeCreated: 1522854548
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,425 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrCameraFade.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using UltimateXR.Animation.Interpolation;
using UltimateXR.Avatar;
using UltimateXR.Core;
using UltimateXR.Core.Components.Composite;
using UltimateXR.Core.Settings;
using UltimateXR.Extensions.System.Threading;
using UltimateXR.Extensions.Unity;
using UltimateXR.Extensions.Unity.Render;
using UnityEngine;
namespace UltimateXR.CameraUtils
{
/// <summary>
/// Component added to a camera that allows to fade the rendered content to and from a color
/// by using a fullscreen quad.
/// </summary>
public class UxrCameraFade : UxrAvatarComponent<UxrCameraFade>
{
#region Public Types & Data
/// <summary>
/// Gets whether the component is currently fading.
/// </summary>
public bool IsFading => DrawFade;
/// <summary>
/// Gets or sets the fade color used. The alpha is determined by the fade itself.
/// </summary>
public Color FadeColor
{
get => _fadeColor;
set => _fadeColor = value;
}
/// <summary>
/// Gets or sets the layer value of the quad that is used to render the fade.
/// </summary>
public int QuadLayer
{
get => _quadLayer;
set
{
_quadLayer = value;
if (_quadObject != null)
{
_quadObject.layer = value;
}
}
}
#endregion
#region Public Methods
/// <summary>
/// Checks if the given camera has a <see cref="UxrCameraFade" /> component. If not it is added to the camera.
/// </summary>
/// <param name="camera">Camera to check</param>
/// <returns>The <see cref="UxrCameraFade" /> component which may have been added or was already present</returns>
public static UxrCameraFade CheckAddToCamera(Camera camera)
{
UxrCameraFade cameraFade = camera.gameObject.GetOrAddComponent<UxrCameraFade>();
cameraFade._fadeColor = Color.black;
return cameraFade;
}
/// <summary>
/// Checks if the given camera has a <see cref="UxrCameraFade" /> component and a fade is currently active.
/// </summary>
/// <param name="camera">Camera to check</param>
/// <returns>
/// True if the camera has a <see cref="UxrCameraFade" /> component attached AND a fade
/// currently running, false otherwise
/// </returns>
public static bool HasCameraFadeActive(Camera camera)
{
UxrCameraFade cameraFade = camera.gameObject.GetComponent<UxrCameraFade>();
return cameraFade != null && cameraFade.DrawFade;
}
/// <summary>
/// Starts a fade over time on the given camera. The camera will fade out to a given color and
/// then fade in from that color again.
/// This is the static helper method that can be used to perform everything in just a single static call.
/// </summary>
/// <param name="camera">The camera to perform the fade on</param>
/// <param name="fadeOutDurationSeconds">Number of seconds of the initial fade-out</param>
/// <param name="fadeInDurationSeconds">Number of seconds of the fade-in</param>
/// <param name="fadeColor">The color the component fades out to and fades in from</param>
/// <param name="fadeOutFinishedCallback">Optional callback executed right after the fade out finished</param>
/// <param name="fadeInFinishedCallback">Optional callback executed right after the fade in finished</param>
public static void StartFade(Camera camera,
float fadeOutDurationSeconds,
float fadeInDurationSeconds,
Color fadeColor,
Action fadeOutFinishedCallback = null,
Action fadeInFinishedCallback = null)
{
UxrCameraFade cameraFade = CheckAddToCamera(camera);
cameraFade.StartFade(fadeOutDurationSeconds, fadeInDurationSeconds, fadeColor, fadeOutFinishedCallback, fadeInFinishedCallback);
}
/// <summary>
/// Starts a fade over time on the camera that has this component. The camera will fade out to a given color and
/// then fade in from that color again.
/// For a coroutine-friendly way of fading check StartFadeCoroutine().
/// </summary>
/// <param name="fadeOutDurationSeconds">Number of seconds of the initial fade-out</param>
/// <param name="fadeInDurationSeconds">Number of seconds of the fade-in</param>
/// <param name="fadeColor">The color the component fades out to and fades in from</param>
/// <param name="fadeOutFinishedCallback">Optional callback that is called just after the fade out finished</param>
/// <param name="fadeInFinishedCallback">Optional callback that is called just after the fade in finished</param>
public void StartFade(float fadeOutDurationSeconds,
float fadeInDurationSeconds,
Color fadeColor,
Action fadeOutFinishedCallback = null,
Action fadeInFinishedCallback = null)
{
if (DrawFade)
{
if (UxrGlobalSettings.Instance.LogLevelAvatar >= UxrLogLevel.Warnings)
{
Debug.LogWarning($"{UxrConstants.AvatarModule} A fade was requested while one already being active. Some callbacks may not be called correctly. ");
}
}
_fadeColor = fadeColor;
DrawFade = true;
_fadeOutFinished = false;
_fadeTimer = fadeOutDurationSeconds + fadeInDurationSeconds;
_fadeOutDuration = fadeOutDurationSeconds;
_fadeInDuration = fadeInDurationSeconds;
_fadeOutFinishedCallback = fadeOutFinishedCallback;
_fadeInFinishedCallback = fadeInFinishedCallback;
_fadeCurrentColor = _fadeColor;
_fadeCurrentColor.a = 0.0f;
FadeMaterial.color = _fadeCurrentColor;
}
/// <summary>
/// Enables the camera fade color. It will draw an overlay with the given color until <see cref="DisableFadeColor" />
/// is called.
/// </summary>
/// <param name="color">The color to draw the overlay with</param>
/// <param name="quantity">The quantity [0.0, 1.0] of the fade</param>
public void EnableFadeColor(Color color, float quantity)
{
DrawFade = true;
_fadeTimer = -1.0f;
_fadeCurrentColor = color;
_fadeCurrentColor.a *= quantity;
FadeMaterial.color = _fadeCurrentColor;
}
/// <summary>
/// Disables the camera fade rendering.
/// </summary>
public void DisableFadeColor()
{
DrawFade = false;
_fadeTimer = -1.0f;
}
/// <summary>
/// Starts a fade over time using an async operation.
/// </summary>
/// <param name="ct">The cancellation token to cancel the async operation</param>
/// <param name="fadeSeconds">The fade duration in seconds</param>
/// <param name="startColor">The fade start color</param>
/// <param name="endColor">The fade end color</param>
public async Task FadeAsync(CancellationToken ct, float fadeSeconds, Color startColor, Color endColor)
{
await TaskExt.Loop(ct,
fadeSeconds,
t =>
{
DrawFade = true;
_fadeCurrentColor = Color.Lerp(startColor, endColor, t);
FadeMaterial.color = _fadeCurrentColor;
},
UxrEasing.Linear,
true);
if (Mathf.Approximately(endColor.a, 0.0f))
{
DrawFade = false;
}
}
#endregion
#region Unity
/// <summary>
/// Initializes all internal data.
/// </summary>
protected override void Awake()
{
base.Awake();
CheckInitialize();
}
/// <summary>
/// Subscribes to events.
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
}
/// <summary>
/// Unsubscribes from events.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
DrawFade = false;
}
#endregion
#region Coroutines
/// <summary>
/// Coroutine that fades the screen over time. It can be used to be yielded externally from another coroutine.
/// <see cref="FadeAsync" /> is provided as the async alternative.
/// </summary>
/// <param name="fadeSeconds">Seconds it will take to execute the fade</param>
/// <param name="startColor">Start color value</param>
/// <param name="endColor">End color value</param>
/// <returns>Coroutine IEnumerator</returns>
public IEnumerator StartFadeCoroutine(float fadeSeconds, Color startColor, Color endColor)
{
if (DrawFade)
{
// Debug.LogWarning($"{UxrConstants.AvatarModule} A fade coroutine was requested while a fade already being active");
}
yield return this.LoopCoroutine(fadeSeconds,
t =>
{
DrawFade = true;
_fadeCurrentColor = Color.Lerp(startColor, endColor, t);
FadeMaterial.color = _fadeCurrentColor;
},
UxrEasing.Linear,
true);
if (Mathf.Approximately(endColor.a, 0.0f))
{
DrawFade = false;
}
}
#endregion
#region Event Handling Methods
/// <summary>
/// Updates the fade (StartFade version) and calls all callbacks when they need to be triggered.
/// </summary>
private void UxrManager_AvatarsUpdated()
{
if (Avatar.AvatarMode == UxrAvatarMode.UpdateExternally)
{
DrawFade = false;
return;
}
if (_fadeTimer > 0.0f)
{
_fadeTimer -= Time.deltaTime;
if (_fadeTimer <= 0.0f)
{
DrawFade = false;
_fadeInFinishedCallback?.Invoke();
}
else if (_fadeTimer < _fadeInDuration && _fadeOutFinished == false)
{
_fadeOutFinished = true;
_fadeCurrentColor.a = 1.0f * _fadeColor.a;
_fadeOutFinishedCallback?.Invoke();
}
else
{
if (_fadeTimer < _fadeInDuration)
{
_fadeCurrentColor.a = Mathf.Clamp01(_fadeTimer / _fadeInDuration) * _fadeColor.a;
}
else
{
_fadeCurrentColor.a = Mathf.Clamp01(1.0f - (_fadeTimer - _fadeInDuration) / _fadeOutDuration) * _fadeColor.a;
}
}
FadeMaterial.color = _fadeCurrentColor;
}
}
#endregion
#region Private Methods
/// <summary>
/// Initializes the component if necessary.
/// </summary>
private void CheckInitialize()
{
if (!_initialized)
{
_initialized = true;
_camera = Avatar.CameraComponent;
_fadeTimer = -1.0f;
DrawFade = false;
CreateCameraQuad();
}
}
/// <summary>
/// Creates the quad to render in front of the camera.
/// </summary>
private void CreateCameraQuad()
{
_quadObject = new GameObject("Fade");
_quadObject.transform.SetParent(transform);
_quadObject.transform.localPosition = Vector3.forward * (_camera.nearClipPlane + 0.01f);
_quadObject.transform.localEulerAngles = new Vector3(0.0f, 180.0f, 0.0f);
_quadObject.layer = _quadLayer;
MeshFilter meshFilter = _quadObject.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = _quadObject.AddComponent<MeshRenderer>();
meshFilter.mesh = MeshExt.CreateQuad(2.0f);
_fadeMaterial = new Material(ShaderExt.UnlitOverlayFade);
meshRenderer.sharedMaterial = _fadeMaterial;
_quadObject.SetActive(_drawFade);
}
#endregion
#region Private Types & Data
/// <summary>
/// Gets the material used to draw the fade.
/// </summary>
private Material FadeMaterial
{
get
{
if (_fadeMaterial == null)
{
_fadeMaterial = new Material(ShaderExt.UnlitTransparentColorNoDepthTest);
}
return _fadeMaterial;
}
}
/// <summary>
/// Gets or sets whether to draw the fade.
/// </summary>
private bool DrawFade
{
get => _drawFade;
set
{
_drawFade = value;
if (_quadObject != null)
{
_quadObject.SetActive(_drawFade);
}
}
}
private Color _fadeColor = Color.black;
private bool _initialized;
private Camera _camera;
private Material _fadeMaterial;
private bool _drawFade;
private bool _fadeOutFinished;
private float _fadeTimer;
private float _fadeInDuration;
private float _fadeOutDuration;
private Color _fadeCurrentColor;
private GameObject _quadObject;
private int _quadLayer = 1;
private Action _fadeOutFinishedCallback;
private Action _fadeInFinishedCallback;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 93ef313dafd5aca45be24ded4844277e
timeCreated: 1505311640
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrCameraWallFade.StateSave.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core.StateSave;
namespace UltimateXR.CameraUtils
{
public partial class UxrCameraWallFade
{
#region Protected Overrides
/// <inheritdoc />
protected override void SerializeState(bool isReading, int stateSerializationVersion, UxrStateSaveLevel level, UxrStateSaveOptions options)
{
base.SerializeState(isReading, stateSerializationVersion, level, options);
// Changes are already handled each frame, we don't serialize them in incremental changes
if (level > UxrStateSaveLevel.ChangesSincePreviousSave)
{
SerializeStateValue(level, options, nameof(_lastValidPos), ref _lastValidPos);
SerializeStateValue(level, options, nameof(_lastValidPosInitialized), ref _lastValidPosInitialized);
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0229924881194652831e4a9dcdc065b2
timeCreated: 1705950993

View File

@@ -0,0 +1,411 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrCameraWallFade.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Avatar;
using UltimateXR.Core;
using UltimateXR.Core.Components.Composite;
using UltimateXR.Extensions.Unity;
using UltimateXR.Extensions.Unity.Render;
using UltimateXR.Locomotion;
using UltimateXR.Manipulation;
using UnityEngine;
namespace UltimateXR.CameraUtils
{
/// <summary>
/// Component added to a camera that enables to fade the camera to black whenever the user tries to stick the head
/// inside geometry. It is used to prevent peeking through walls.
/// It is also often consulted by <see cref="UxrLocomotion" /> components to check whether the avatar can move around
/// in order to prevent cheating through walls.
/// </summary>
[RequireComponent(typeof(Camera))]
public partial class UxrCameraWallFade : UxrAvatarComponent<UxrCameraWallFade>
{
#region Inspector Properties/Serialized Fields
[SerializeField] private UxrWallFadeMode _mode = UxrWallFadeMode.AllowTraverse;
[SerializeField] private LayerMask _collisionLayers;
[SerializeField] private bool _ignoreTriggerColliders = true;
[SerializeField] private bool _ignoreDynamicObjects = true;
[SerializeField] private bool _ignoreGrabbedObjects = true;
[SerializeField] private Color _fadeColor;
[SerializeField] private float _fadeFarDistance = 0.24f;
[SerializeField] private float _fadeNearDistance = 0.12f;
#endregion
#region Public Types & Data
/// <summary>
/// Gets whether the camera is currently inside a wall.
/// </summary>
public bool IsInsideWall { get; private set; }
/// <summary>
/// Gets or sets the current working mode.
/// </summary>
public UxrWallFadeMode Mode
{
get => _mode;
set
{
_mode = value;
_lastValidPosInitialized = false;
}
}
#endregion
#region Public Methods
/// <summary>
/// Checks whether an avatar is currently peeking through geometry. The camera object requires to have an
/// <see cref="UxrCameraFade" /> in order to work.
/// </summary>
/// <param name="avatar">The avatar to check</param>
/// <returns>
/// Whether the avatar has an <see cref="UxrCameraFade" /> component and it currently detects the avatar is
/// peeking through geometry
/// </returns>
public static bool IsAvatarPeekingThroughGeometry(UxrAvatar avatar)
{
if (avatar == null)
{
return false;
}
UxrCameraWallFade wallFade = avatar.CameraComponent != null ? avatar.CameraComponent.GetComponent<UxrCameraWallFade>() : null;
return wallFade && wallFade._quadObject.activeSelf; //.IsInsideWall;
}
#endregion
#region Unity
/// <summary>
/// Initializes the component.
/// </summary>
protected override void Awake()
{
base.Awake();
CreateCameraQuad();
}
/// <summary>
/// Subscribes to events. It also initializes the component so that whenever it is enabled, it is considered as being
/// "outside".
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
_lastValidPosInitialized = false;
UxrAvatar.GlobalAvatarMoved += UxrAvatar_GlobalAvatarMoved;
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
}
/// <summary>
/// Unsubscribes from events.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
UxrAvatar.GlobalAvatarMoved -= UxrAvatar_GlobalAvatarMoved;
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
if (_quadObject != null)
{
_quadObject.SetActive(false);
}
}
#endregion
#region Event Handling Methods
/// <summary>
/// Called whenever an avatar moved. The state is reset so that it is considered "outside".
/// </summary>
/// <param name="sender">Event sender</param>
/// <param name="e">Event parameters</param>
private void UxrAvatar_GlobalAvatarMoved(object sender, UxrAvatarMoveEventArgs e)
{
if (ReferenceEquals(sender, Avatar))
{
_lastValidPosInitialized = false;
}
}
/// <summary>
/// Called after all avatars have been updated. This is where the component is updated.
/// </summary>
private void UxrManager_AvatarsUpdated()
{
if (Avatar.AvatarMode != UxrAvatarMode.Local)
{
if (_quadObject)
{
_quadObject.SetActive(false);
}
}
else
{
UpdateFade();
}
}
#endregion
#region Private Methods
/// <summary>
/// Updates the component using the current <see cref="UxrWallFadeMode" /> algorithm described by <see cref="Mode" />.
/// </summary>
private void UpdateFade()
{
if (_lastValidPosInitialized == false && Avatar != null && Avatar.transform.InverseTransformPoint(transform.position).y > CameraInitializationMinY)
{
// We assume the camera starts in a valid state
_lastValidPosInitialized = true;
_lastValidPos = transform.position;
_fadeAlpha = 0.0f;
IsInsideWall = false;
}
if (_lastValidPosInitialized)
{
_fadeAlpha = 0.0f;
// First check if we are inside a wall or not using the last valid position
Vector3 cameraDeltaPos = transform.position - _lastValidPos;
// We cast rays in both directions, from the last valid position to the current position. We will look for transitions
// from inside to outside a wall or the other way around by looking at the number of intersections in both directions
RaycastHit[] raycastHitsFromLasValidPos = Physics.RaycastAll(_lastValidPos,
cameraDeltaPos.normalized,
cameraDeltaPos.magnitude,
_collisionLayers,
_ignoreTriggerColliders ? QueryTriggerInteraction.Ignore : QueryTriggerInteraction.Collide);
RaycastHit[] raycastHitsToLastValidPos = Physics.RaycastAll(transform.position,
-cameraDeltaPos.normalized,
cameraDeltaPos.magnitude,
_collisionLayers,
_ignoreTriggerColliders ? QueryTriggerInteraction.Ignore : QueryTriggerInteraction.Collide);
int raycastCountFromLastValidPos = GetRaycastCount(raycastHitsFromLasValidPos);
int raycastCountToLastValidPos = GetRaycastCount(raycastHitsToLastValidPos);
if (_mode == UxrWallFadeMode.AllowTraverse)
{
if (IsInsideWall == false && raycastCountFromLastValidPos > raycastCountToLastValidPos)
{
// From outside a wall to inside a wall
IsInsideWall = true;
}
else if (IsInsideWall && raycastCountFromLastValidPos <= raycastCountToLastValidPos)
{
// From inside a wall to outside a wall
IsInsideWall = false;
}
}
else if (_mode == UxrWallFadeMode.Strict)
{
IsInsideWall = raycastCountFromLastValidPos > 0 || raycastCountToLastValidPos > 0;
}
_fadeAlpha = IsInsideWall ? 1.0f : 0.0f;
// If we are not inside a wall we will wrap the camera in a cylinder and get directions from which we will cast rays to check if they intersect with the scene
// and fade the screen accordingly
if (IsInsideWall == false)
{
for (int heightSubdivision = 0; heightSubdivision < CameraCylinderVerticalSteps; ++heightSubdivision)
{
float height = Mathf.Lerp(-_fadeFarDistance, _fadeFarDistance, heightSubdivision / (CameraCylinderVerticalSteps - 1.0f));
for (int radiusIndex = 0; radiusIndex < CameraCylinderSides; ++radiusIndex)
{
float offsetT = 1.0f / CameraCylinderSides * 0.5f;
float radians = Mathf.PI * 2.0f * (radiusIndex * (1.0f / CameraCylinderSides) + offsetT);
Vector3 direction = new Vector3(Mathf.Cos(radians), height, Mathf.Sin(radians)).normalized;
RaycastHit[] raycastHits = Physics.RaycastAll(transform.position,
transform.TransformDirection(direction),
_fadeFarDistance,
_collisionLayers,
_ignoreTriggerColliders ? QueryTriggerInteraction.Ignore : QueryTriggerInteraction.Collide);
if (GetClosestRaycast(raycastHits, out RaycastHit hit))
{
// We are close enough to a collider to start fading out
float interval = _fadeFarDistance - _fadeNearDistance;
float alpha = hit.distance < _fadeNearDistance ? 1.0f :
interval > 0.0f ? 1.0f - (hit.distance - _fadeNearDistance) / interval : 1.0f;
if (alpha > _fadeAlpha)
{
// We are close to a wall.
_fadeAlpha = Mathf.Clamp01(alpha);
}
}
}
}
}
// Update last valid position if it is far enough from the wall to avoid floating point errors (we use 1cm threshold which is the minimum near clip plane for the camera)
if (IsInsideWall == false)
{
if (Physics.CheckSphere(transform.position,
0.01f,
_collisionLayers,
_ignoreTriggerColliders ? QueryTriggerInteraction.Ignore : QueryTriggerInteraction.Collide) == false)
{
_lastValidPos = transform.position;
}
}
_quadObject.SetActive(_fadeAlpha > 0.0f);
_fadeMaterial.color = _fadeColor.WithAlpha(_fadeAlpha);
}
else
{
_quadObject.SetActive(false);
_fadeAlpha = 0.0f;
}
}
/// <summary>
/// Creates the quad that is used to render the fullscreen fade.
/// </summary>
private void CreateCameraQuad()
{
Camera camera = GetComponent<Camera>();
_quadObject = new GameObject("Fade");
_quadObject.transform.SetParent(transform);
_quadObject.transform.localPosition = Vector3.forward * (camera.nearClipPlane + 0.01f);
_quadObject.transform.localEulerAngles = new Vector3(0.0f, 180.0f, 0.0f);
Mesh mesh = MeshExt.CreateQuad(2.0f);
MeshFilter meshFilter = _quadObject.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = _quadObject.AddComponent<MeshRenderer>();
meshFilter.mesh = mesh;
_fadeMaterial = new Material(ShaderExt.UnlitOverlayFade);
meshRenderer.sharedMaterial = _fadeMaterial;
_quadObject.SetActive(false);
}
/// <summary>
/// Checks whether the given raycast collider hit is valid or should be ignored.
/// </summary>
/// <param name="colliderHit">Collider that was hit</param>
/// <returns>Whether the given raycast collider hit is valid</returns>
private bool IsValidRaycastHit(Collider colliderHit)
{
if (_ignoreDynamicObjects)
{
// Check for rigidbody and ignore if found
if (colliderHit.gameObject.IsDynamic())
{
return false;
}
}
if (_ignoreGrabbedObjects)
{
UxrGrabbableObject grabbableObject = colliderHit.GetComponentInParent<UxrGrabbableObject>();
if (grabbableObject && grabbableObject.IsBeingGrabbed)
{
return false;
}
}
return !colliderHit.gameObject.GetComponentInParent<UxrIgnoreWallFade>() && !colliderHit.gameObject.GetComponentInParent<UxrAvatar>();
}
/// <summary>
/// Gets the number of raycast hits that are valid from the given set.
/// </summary>
/// <param name="raycastHits">The set of raycast hits</param>
/// <returns>The valid number of hits</returns>
private int GetRaycastCount(RaycastHit[] raycastHits)
{
int count = 0;
foreach (RaycastHit hit in raycastHits)
{
if (IsValidRaycastHit(hit.collider))
{
count++;
}
}
return count;
}
/// <summary>
/// Gets the closest valid raycast hit from the set.
/// </summary>
/// <param name="raycastHits">The raycast to get the closest valid from</param>
/// <param name="raycastHit">Returns the closest valid raycast</param>
/// <returns>Whether a valid raycast was found</returns>
private bool GetClosestRaycast(RaycastHit[] raycastHits, out RaycastHit raycastHit)
{
int closestIndex = -1;
float closestDistance = float.MaxValue;
for (int i = 0; i < raycastHits.Length; ++i)
{
if (IsValidRaycastHit(raycastHits[i].collider))
{
// Keep closest hit
if (raycastHits[i].distance < closestDistance)
{
closestIndex = i;
closestDistance = raycastHits[i].distance;
}
}
}
if (closestIndex != -1)
{
raycastHit = raycastHits[closestIndex];
return true;
}
raycastHit = new RaycastHit();
return false;
}
#endregion
#region Private Types & Data
/// <summary>
/// Used to avoid initialization being done before user has headset in correct position.
/// </summary>
private const float CameraInitializationMinY = 0.2f;
private const float CameraCylinderSides = 8;
private const float CameraCylinderVerticalSteps = 2;
private Vector3 _lastValidPos;
private bool _lastValidPosInitialized;
private GameObject _quadObject;
private Material _fadeMaterial;
private float _fadeAlpha;
#endregion
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 13e10b2b122c8014ca43f12f5be3d59a
timeCreated: 1519759847
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrIgnoreWallFade.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core.Components;
namespace UltimateXR.CameraUtils
{
/// <summary>
/// Added to a GameObject will tell the <see cref="UxrCameraWallFade" /> component to ignore any collision with it or
/// any other GameObject that hangs from the tree.
/// </summary>
public class UxrIgnoreWallFade : UxrComponent
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54bafa17bd62c4c4d935fa0a797b85dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrWallFadeMode.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace UltimateXR.CameraUtils
{
/// <summary>
/// Enumerates the different working modes for <see cref="UxrCameraWallFade" />.
/// </summary>
public enum UxrWallFadeMode
{
/// <summary>
/// Fades to black when getting inside the geometry but allows to traverse and exit through the other side.
/// </summary>
AllowTraverse,
/// <summary>
/// Doesn't allow traversing. The condition to fade-in back again is that the camera needs to have a straight line
/// without any traversing between the point where the head got in and the current position.
/// </summary>
Strict
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 50c504e842a34323bc0474ed43301a71
timeCreated: 1645655330