246 lines
7.8 KiB
C#
246 lines
7.8 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using UnityEngine;
|
|
|
|
namespace Microsoft.MixedReality.Toolkit.UI
|
|
{
|
|
/// <summary>
|
|
/// A background with 'fake' inertia
|
|
/// Useful for soft or liquid objects
|
|
/// </summary>
|
|
[AddComponentMenu("Scripts/MRTK/SDK/ToolTipBackgroundBlob")]
|
|
public class ToolTipBackgroundBlob : MonoBehaviour, IToolTipBackground
|
|
{
|
|
// Which transforms to use for each type of distortion
|
|
// See the ToolTipBalloon prefab for an example of which transforms to target
|
|
#region Transform Targets
|
|
|
|
[Header("Transform targets")]
|
|
[SerializeField]
|
|
private Transform positionTarget = null;
|
|
|
|
[SerializeField]
|
|
private Transform rotationTarget = null;
|
|
|
|
[SerializeField]
|
|
private Transform distortionTarget = null;
|
|
|
|
[SerializeField]
|
|
private Transform attachPointOffset = null;
|
|
|
|
[SerializeField]
|
|
private ToolTip toolTip = null;
|
|
|
|
#endregion Transform Targets
|
|
|
|
/// <summary>
|
|
/// Determines whether background of Tooltip is visible.
|
|
/// </summary>
|
|
public bool IsVisible
|
|
{
|
|
set
|
|
{
|
|
if (BackgroundRenderer)
|
|
{
|
|
BackgroundRenderer.enabled = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Header("Blob settings")]
|
|
[SerializeField]
|
|
[Range(0f, 5f)]
|
|
private float blobInertia = 0.5f;
|
|
|
|
public float BlobInertia
|
|
{
|
|
get
|
|
{
|
|
return blobInertia;
|
|
}
|
|
set
|
|
{
|
|
blobInertia = Mathf.Clamp(value, 0, maxInertia);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0f, 1f)]
|
|
private float blobDistortion = 0.1f;
|
|
|
|
public float BlobDistortion
|
|
{
|
|
get
|
|
{
|
|
return blobDistortion;
|
|
}
|
|
set
|
|
{
|
|
blobDistortion = Mathf.Clamp(value, 0, maxDistortion);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0f, 1f)]
|
|
private float blobRotation = 0.1f;
|
|
|
|
public float BlobRotation
|
|
{
|
|
get
|
|
{
|
|
return blobRotation;
|
|
}
|
|
set
|
|
{
|
|
blobRotation = Mathf.Clamp(value, 0, maxRotation);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0.1f, 5f)]
|
|
private float positionCorrectionStrength = 1f;
|
|
|
|
public float PositionCorrectionStrength
|
|
{
|
|
get
|
|
{
|
|
return positionCorrectionStrength;
|
|
}
|
|
set
|
|
{
|
|
positionCorrectionStrength = Mathf.Clamp(value, minPositionCorrection, maxPositionCorrection);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0.1f, 5f)]
|
|
private float distortionCorrectionStrength = 1f;
|
|
|
|
public float DistortionCorrectionStrength
|
|
{
|
|
get
|
|
{
|
|
return distortionCorrectionStrength;
|
|
}
|
|
set
|
|
{
|
|
distortionCorrectionStrength = Mathf.Clamp(value, minDistortionCorrection, maxDistortionCorrection);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range(0.1f, 5f)]
|
|
private float rotationCorrectionStrength = 1f;
|
|
|
|
public float RotationCorrectionStrength
|
|
{
|
|
get
|
|
{
|
|
return rotationCorrectionStrength;
|
|
}
|
|
set
|
|
{
|
|
rotationCorrectionStrength = Mathf.Clamp(value, minRotationCorrection, maxRotationCorrection);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private Vector3 blobOffset;
|
|
|
|
public Vector3 BlobOffset
|
|
{
|
|
get
|
|
{
|
|
return blobOffset;
|
|
}
|
|
set
|
|
{
|
|
blobOffset = value;
|
|
}
|
|
}
|
|
|
|
private const float maxInertia = 5f;
|
|
private const float maxDistortion = 1f;
|
|
private const float maxRotation = 1f;
|
|
private const float minPositionCorrection = 0.1f;
|
|
private const float minDistortionCorrection = 0.1f;
|
|
private const float minRotationCorrection = 0.1f;
|
|
private const float maxPositionCorrection = 5f;
|
|
private const float maxDistortionCorrection = 5f;
|
|
private const float maxRotationCorrection = 5f;
|
|
|
|
private readonly Bounds defaultBounds = new Bounds(Vector3.zero, Vector3.one);
|
|
|
|
private MeshFilter backgroundRendererMeshFilter;
|
|
private Vector3 lastPosition;
|
|
private Vector3 velocity;
|
|
private Vector3 distortion;
|
|
private Vector3 rotation;
|
|
private Bounds localContentBounds;
|
|
private Bounds inertialContentBounds;
|
|
|
|
/// <summary>
|
|
/// Mesh renderer for mesh background.
|
|
/// </summary>
|
|
public MeshRenderer BackgroundRenderer;
|
|
|
|
private void OnEnable()
|
|
{
|
|
lastPosition = positionTarget.position;
|
|
inertialContentBounds = defaultBounds;
|
|
localContentBounds = defaultBounds;
|
|
velocity = Vector3.zero;
|
|
backgroundRendererMeshFilter = BackgroundRenderer.GetComponent<MeshFilter>();
|
|
}
|
|
|
|
public void OnContentChange(Vector3 localContentSize, Vector3 localContentOffset, Transform contentParentTransform)
|
|
{
|
|
|
|
// Get the size of the mesh and use this to adjust the local content size on the x / y axis
|
|
// This will accommodate meshes that aren't built to 1,1 scale
|
|
Bounds meshBounds = backgroundRendererMeshFilter.sharedMesh.bounds;
|
|
localContentSize.x /= meshBounds.size.x;
|
|
localContentSize.y /= meshBounds.size.y;
|
|
localContentSize.z = 1;
|
|
|
|
localContentBounds.size = Vector3.one; // localContentSize;
|
|
localContentBounds.center = localContentOffset;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// Adjust center and size by velocity
|
|
Vector3 currentPosition = positionTarget.position;
|
|
velocity = Vector3.Lerp(velocity, lastPosition - currentPosition, 1f / blobInertia * Time.deltaTime);
|
|
Vector3 currentDistortion = -velocity * blobDistortion;
|
|
distortion = Vector3.Lerp(distortion, currentDistortion, 1f / blobDistortion * Time.deltaTime);
|
|
|
|
inertialContentBounds.center += velocity;
|
|
Vector3 size = inertialContentBounds.size + distortion;
|
|
inertialContentBounds.size = size;
|
|
|
|
Vector3 currentRotation = Vector3.zero;
|
|
currentRotation.x = velocity.x * 360;
|
|
currentRotation.z = velocity.z * 360;
|
|
currentRotation.y = velocity.y * 360;
|
|
currentRotation = rotationTarget.TransformDirection(currentRotation);
|
|
rotation = Vector3.Lerp(rotation, currentRotation, 1f / blobRotation * Time.deltaTime);
|
|
|
|
// Correct the center and size
|
|
inertialContentBounds.center = Vector3.Lerp(inertialContentBounds.center, localContentBounds.center, Time.deltaTime * positionCorrectionStrength);
|
|
inertialContentBounds.size = Vector3.Lerp(inertialContentBounds.size, localContentBounds.size, Time.deltaTime * distortionCorrectionStrength);
|
|
rotationTarget.localRotation = Quaternion.Lerp(positionTarget.localRotation, Quaternion.identity, Time.deltaTime * rotationCorrectionStrength);
|
|
|
|
// Apply the center and size
|
|
positionTarget.localPosition = inertialContentBounds.center + blobOffset;
|
|
distortionTarget.localScale = inertialContentBounds.size;
|
|
rotationTarget.Rotate(velocity * blobRotation * 360);
|
|
|
|
// Adjust the tool tip attach position
|
|
toolTip.AttachPointPosition = attachPointOffset.position;
|
|
|
|
lastPosition = currentPosition;
|
|
}
|
|
}
|
|
} |