VRTK_Slider doesn't work at all - with oculus rift
See original GitHub issueEnvironment
- Source of VRTK: Github
- Version of VRTK:
- Version of Unity3D: 5.5.3f1
- Hardware used: Oculus Rift + Touch
- SDK used: Oculus Utilities + Avatar
Steps to reproduce
- Open example scene 025.
- Try to grab and move any slider.
- Observe how the slider won’t move at all.
Expected behavior
The sliders should move.
Current behavior
The sliders don’t follow the controller and stay fixed in their initial position.
I tried fixing this but can’t make the current snapToStep
feature work. I suggest using the top left slider on the wall and set
Released Friction
to5
(We want to get back the old slider behavior where you can flick the slider, currently this doesn’t work even when this setting is0
.)Step Size
to10
(To test whetherSnap To Step
works.)
Then make sure to test both Snap To Step
false
and true
.
Here’s what I’ve changed it to:
// Slider|Controls3D|100090
namespace VRTK
{
using UnityEngine;
/// <summary>
/// Attaching the script to a game object will allow the user to interact with it as if it were a horizontal or vertical slider. The direction can be freely set and auto-detection is supported.
/// </summary>
/// <remarks>
/// The script will instantiate the required Rigidbody and Interactable components automatically in case they do not exist yet.
/// </remarks>
/// <example>
/// `VRTK/Examples/025_Controls_Overview` has a selection of sliders at various angles with different step values to demonstrate their usage.
/// </example>
public class VRTK_Slider : VRTK_Control
{
[Tooltip("An optional game object to which the wheel will be connected. If the game object moves the wheel will follow along.")]
public GameObject connectedTo;
[Tooltip("The axis on which the slider should move. All other axis will be frozen.")]
public Direction direction = Direction.autodetect;
[Tooltip("The collider to specify the minimum limit of the slider.")]
public Collider minimumLimit;
[Tooltip("The collider to specify the maximum limit of the slider.")]
public Collider maximumLimit;
[Tooltip("The minimum value of the slider.")]
public float minimumValue = 0f;
[Tooltip("The maximum value of the slider.")]
public float maximumValue = 100f;
[Tooltip("The increments in which slider values can change.")]
public float stepSize = 0.1f;
[Tooltip("If this is checked then when the slider is released, it will snap to the nearest value position.")]
public bool snapToStep = false;
[Tooltip("The amount of friction the slider will have when it is released.")]
public float releasedFriction = 50f;
protected Direction finalDirection;
protected Rigidbody sliderRigidbody;
protected ConfigurableJoint sliderJoint;
protected bool sliderJointCreated = false;
protected Vector3 minimumLimitDiff;
protected Vector3 maximumLimitDiff;
protected Vector3 snapPosition;
protected override void OnDrawGizmos()
{
base.OnDrawGizmos();
if (!enabled || !setupSuccessful)
{
return;
}
Gizmos.DrawLine(transform.position, minimumLimit.transform.position);
Gizmos.DrawLine(transform.position, maximumLimit.transform.position);
}
protected override void InitRequiredComponents()
{
DetectSetup();
InitRigidbody();
InitInteractableObject();
InitJoint();
}
protected override bool DetectSetup()
{
if (sliderJointCreated)
{
if (connectedTo)
{
sliderJoint.connectedBody = connectedTo.GetComponent<Rigidbody>();
}
}
finalDirection = direction;
if (direction == Direction.autodetect)
{
RaycastHit hitRight;
RaycastHit hitUp;
RaycastHit hitForward;
bool rightHasHit = Physics.Raycast(transform.position, transform.right, out hitRight);
bool upHasHit = Physics.Raycast(transform.position, transform.up, out hitUp);
bool forwardHasHit = Physics.Raycast(transform.position, transform.forward, out hitForward);
Vector3 sliderDiff = transform.localScale / 2f;
//The right ray has found the min on the right, so max is on the left
if (rightHasHit && hitRight.collider.gameObject.Equals(minimumLimit.gameObject))
{
finalDirection = Direction.x;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.right, minimumLimit.transform.localScale.x, sliderDiff.x, false);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.right, maximumLimit.transform.localScale.x, sliderDiff.x, true);
}
//The right ray has found the max on the right, so min is on the left
if (rightHasHit && hitRight.collider.gameObject.Equals(maximumLimit.gameObject))
{
finalDirection = Direction.x;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.right, minimumLimit.transform.localScale.x, sliderDiff.x, true);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.right, maximumLimit.transform.localScale.x, sliderDiff.x, false);
}
// the up ray has found the min above, so max is below
if (upHasHit && hitUp.collider.gameObject.Equals(minimumLimit.gameObject))
{
finalDirection = Direction.y;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.up, minimumLimit.transform.localScale.y, sliderDiff.y, false);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.up, maximumLimit.transform.localScale.y, sliderDiff.y, true);
}
//the up ray has found the max above, so the min ix below
if (upHasHit && hitUp.collider.gameObject.Equals(maximumLimit.gameObject))
{
finalDirection = Direction.y;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.up, minimumLimit.transform.localScale.y, sliderDiff.y, true);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.up, maximumLimit.transform.localScale.y, sliderDiff.y, false);
}
//the forward ray has found the min in front, so the max is behind
if (forwardHasHit && hitForward.collider.gameObject.Equals(minimumLimit.gameObject))
{
finalDirection = Direction.z;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.forward, minimumLimit.transform.localScale.y, sliderDiff.y, false);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.forward, maximumLimit.transform.localScale.y, sliderDiff.y, true);
}
//the forward ray has found the max in front, so the min is behind
if (forwardHasHit && hitForward.collider.gameObject.Equals(maximumLimit.gameObject))
{
finalDirection = Direction.z;
minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.forward, minimumLimit.transform.localScale.z, sliderDiff.z, true);
maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.forward, maximumLimit.transform.localScale.z, sliderDiff.z, false);
}
}
return true;
}
protected override ControlValueRange RegisterValueRange()
{
return new ControlValueRange()
{
controlMin = minimumValue,
controlMax = maximumValue
};
}
protected override void HandleUpdate()
{
CalculateValue();
if (sliderRigidbody.velocity.x != 0)
{
Debug.Log(sliderRigidbody.velocity.x);
}
if (snapToStep && sliderRigidbody.velocity.x == 0)
{
SnapToValue();
}
}
protected virtual Vector3 CalculateDiff(Vector3 initialPosition, Vector3 givenDirection, float scaleValue, float diffMultiplier, bool addition)
{
var additionDiff = givenDirection * diffMultiplier;
var limitDiff = givenDirection * (scaleValue / 2f);
if (addition)
{
limitDiff = initialPosition + limitDiff;
}
else
{
limitDiff = initialPosition - limitDiff;
}
var answer = initialPosition - limitDiff;
if (addition)
{
answer -= additionDiff;
}
else
{
answer += additionDiff;
}
return answer;
}
protected virtual void InitRigidbody()
{
sliderRigidbody = GetComponent<Rigidbody>();
if (sliderRigidbody == null)
{
sliderRigidbody = gameObject.AddComponent<Rigidbody>();
}
sliderRigidbody.isKinematic = false;
sliderRigidbody.useGravity = false;
sliderRigidbody.constraints = RigidbodyConstraints.FreezeRotation;
sliderRigidbody.drag = releasedFriction;
if (connectedTo)
{
Rigidbody connectedToRigidbody = connectedTo.GetComponent<Rigidbody>();
if (connectedToRigidbody == null)
{
connectedToRigidbody = connectedTo.AddComponent<Rigidbody>();
connectedToRigidbody.useGravity = false;
connectedToRigidbody.isKinematic = true;
}
}
}
protected virtual void InitInteractableObject()
{
VRTK_InteractableObject sliderInteractableObject = GetComponent<VRTK_InteractableObject>();
if (sliderInteractableObject == null)
{
sliderInteractableObject = gameObject.AddComponent<VRTK_InteractableObject>();
}
sliderInteractableObject.isGrabbable = true;
sliderInteractableObject.grabAttachMechanicScript = gameObject.AddComponent<GrabAttachMechanics.VRTK_TrackObjectGrabAttach>();
sliderInteractableObject.secondaryGrabActionScript = gameObject.AddComponent<SecondaryControllerGrabActions.VRTK_SwapControllerGrabAction>();
sliderInteractableObject.grabAttachMechanicScript.precisionGrab = true;
sliderInteractableObject.stayGrabbedOnTeleport = false;
sliderInteractableObject.InteractableObjectGrabbed += InteractableObjectGrabbed;
sliderInteractableObject.InteractableObjectUngrabbed += InteractableObjectUngrabbed;
}
protected virtual void InteractableObjectGrabbed(object sender, InteractableObjectEventArgs e)
{
sliderRigidbody.drag = 0;
}
protected virtual void InteractableObjectUngrabbed(object sender, InteractableObjectEventArgs e)
{
sliderRigidbody.drag = releasedFriction;
}
protected virtual void InitJoint()
{
sliderJoint = GetComponent<ConfigurableJoint>();
if (sliderJoint == null)
{
sliderJoint = gameObject.AddComponent<ConfigurableJoint>();
}
sliderJoint.xMotion = (finalDirection == Direction.x ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
sliderJoint.yMotion = (finalDirection == Direction.y ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
sliderJoint.zMotion = (finalDirection == Direction.z ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
sliderJoint.angularXMotion = ConfigurableJointMotion.Locked;
sliderJoint.angularYMotion = ConfigurableJointMotion.Locked;
sliderJoint.angularZMotion = ConfigurableJointMotion.Locked;
ToggleSpring(true);
sliderJointCreated = true;
}
protected virtual void CalculateValue()
{
Vector3 minPoint = minimumLimit.transform.localPosition - minimumLimitDiff;
Vector3 maxPoint = maximumLimit.transform.localPosition - maximumLimitDiff;
float maxDistance = Vector3.Distance(minPoint, maxPoint);
float currentDistance = Vector3.Distance(minPoint, transform.localPosition);
float currentValue = Mathf.Round((minimumValue + Mathf.Clamp01(currentDistance / maxDistance) * (maximumValue - minimumValue)) / stepSize) * stepSize;
float flatValue = currentValue - minimumValue;
float controlRange = maximumValue - minimumValue;
float actualPosition = (flatValue / controlRange);
snapPosition = minPoint + ((maxPoint - minPoint) * actualPosition);
value = currentValue;
}
protected virtual void ToggleSpring(bool state)
{
JointDrive snapDriver = new JointDrive();
snapDriver.positionSpring = (state ? 10000f : 0f);
snapDriver.positionDamper = (state ? 10f : 0f);
snapDriver.maximumForce = (state ? 100f : 0f);
sliderJoint.xDrive = snapDriver;
sliderJoint.yDrive = snapDriver;
sliderJoint.zDrive = snapDriver;
}
protected virtual void SnapToValue()
{
sliderJoint.targetPosition = snapPosition * -1f;
sliderJoint.targetVelocity = Vector3.zero;
Debug.Log("Snapped");
}
}
}
Issue Analytics
- State:
- Created 6 years ago
- Comments:15 (11 by maintainers)
Top Results From Across the Web
Resolved - VR UI Slider Issues
Using the Unity XR Plugin for Oculus Quest. ... I confirm that the UI slider doesn't work at all when I "Play" inside...
Read more >Slider (step slider) doesn't work on iOS & android device
I'm using MRTK slider for my AR app and it works as expected on hololens 2, but now when I build it for...
Read more >My Render Resolution slider is not working on Oculus ...
My Render Resolution slider is not working on Oculus quest 2. Seems whatever I have it set at all my games look blurry....
Read more >Unity VR - Oculus Developer Forum - Meta Community Forums
Hi, I am experiencing a major performance spike while working with the OVRPlugin v. 1.38.1 and Oculus 2018.3.6f1. If I have my PlayerPrefab...
Read more >Sliders - MRTK 2
Sliders work on AR and VR, using motion controllers, hands, or Gesture + Voice. Example scene. You can find examples in the SliderExample...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I know what the problem is!
SteamVR changes the
Settings -> TimeManager -> Fixed TimeStep
value to0.011111
Oculus SDK doesn’t change it, so it stays at the default
0.02
This additional TimeStep is what causes the slider not to work properly
Urgh, damn you Oculus!
I’ll hook up the rift next week and take a look. I need to look at your PR anyway :p