For anyone whose dial is "not responding" to grabs, you MUST have an "XR Direct Interactor" and a collider that is a trigger on the hand you are grabbing with. Great video! Students in my classes will be using this as part of their VR dev training!
Just found this channel, amazing stuff. Also nice to see how you set up your code, I've been figuring out how to do lots of stuff, but all my code is an absolute mess. Keep up the videos!
Fantastic! It was really easy to extend your code to allow for minimum and maximum values, looking for specific values, etc. Great for puzzle games! Do you think you could do a follow-up for levers and sliders?
@@UnityVR Awesome. Levers especially. I've got one working that utilizes Hinge Joints, but that means that it's nearly impossible to have it be attached to another grabbable like I had the dial. An unfortunate limitation. Perhaps you'll have a more elegant solution in mind!
How are you implementing Min / Max values . I am trying mathf.clamp on a Rotation float inside RotateDialClockwise(). I can clamp clock wise rotation between eg : 0 - 90f but cant work out how to clamp anti clockwise between 270 - 360 Im not sure that this is the best solution anyway . Any advise would be greatly appreciated .
Hi Daniel I know this is an old ish video and I am enjoying your videos and apply them to my project but I do have a question as I have only just started is it possible to use this to move through an animation for example if I turn a dial clock wise it will go forward a couple of seconds every 25 degrees and the same backwards when you turn it anti-clockwise just to put this in to context I am making a machine that when you turn a dial it changes the position of a part
Thanks for another great video! I have a slight problem as my dial spins constantly as soon as I rotate just a little to either side. I believe I am using a newer version so I guess something might have changed...
Would it be possible to have dials be attached to other grabbable objects such as a dial that is attached to a remote control that you can grab with the other hand? EDIT: It turns out that, with this system there is no reason to use XRGrabInteractable at all! You can just as easily use XRSimpleInteractable instead, allowing players to mount the dial to other grabbables, moving objects, etc.!
Thanks for the clear concise run through. Would it be possible to update Rotator.cs to deal with updated XR Framework 2.0 , as it seems that certain features are now depreciated. ( ? I think ? ) my error is : when switchCollider is entered NullReferenceException: Object reference not set to an instance of an object LevelUP.Dial.Rotator.GrabbedBy (UnityEngine.XR.Interaction.Toolkit.SelectEnterEventArgs arg0) (at Assets/LevelUpTutorialAssets/Scripts/Dials/Rotator.cs:42) is below now broken ? ( line 42 on Rotator.cs) interactor = GetComponent().selectingInteractor; interactor.GetComponent().hideControllerOnSelect = true; I downloaded the code from source ,just to test the functionality. With intention of replicating. would love to get this working . Cheers
SOLVED: As usual my fault . User error. The fact not being able reference the interactor, because I was using RAY interactor. i was attempting this because Direct Interactor was not interacting in any way at all. At least with ray i was getting a collision response. You have to use Direct Interactor ( as stated ) BUT it also needs a Trigger Collider.
Thanks for your tutorial 🔥🔥,but i found a problem, when i rotate, the dial is out of its parent, is there any solution for that.... i hope you reply🙌🙌 thanks
Great tutorial!, hmm how would you do buttons, i tried to do the Vr versions with hinge joints, but im then forced to have an other collider or object to push em
dont want to use OnTriggerEnter/Exit/Stay? You could get the bounds and move the button accordingly within the range in the OnTriggerStay method. Thats how Ive made most of my VR UI. Most methods require the use of physics though unfortunately.
@@UnityVR have been looking at the escaperoom exaple button, but it behaves a bit weirdly, they are using sweeptest to determine if some rigidbody is close, but it seems to trigger far away from the hand :)
I get errors in this lines, grabInteractor.selectEntered.AddListener(GrabbedBy); grabInteractor.selectExited.AddListener(GrabEnd); does the script work in 2019.4 version?
@@UnityVR I edited it to this and it worked in 2019.4 grabInteractor.onSelectEntered.RemoveListener(GrabbedBy); grabInteractor.onSelectExited.RemoveListener(GrabEnd); } thanks for your tutorials
First: great tutorials! Thanks for that. I have one problem. I don't know why but the controller (hand) is not hiding on select. So I see two hands if I interact with the dial. I've tries everyting and checked all my settings but I can't find the problem. I expect it has something to do with the newer version of the XR Interaction Toolkit. Am I the only one with this problem? Or has someone have the same problem and has a solution? Thanks :-)
@@UnityVR I'm using version 1.0.0-pre.3 and when I select "Hide Controller On Select" i still see the hand for all the interactions. The dial turn works but I see 2 hands when I try it. I also tried the Room-Scale XR Rig (provided by Unity) and than the hand will hide like it should. Also I tried deactivating de Left and Right Teleport Controller entirely and than it works also like expected.
Ok, I've fixed it. For everybody who is interested this is what I did (for both hands): - in the "Teleport Controller / On Teleport Activate" add the "rotation offset" GameObject from the TeleportController GameObject and do GameObject.SetActive (true) - in the "Teleport Controller / On Teleport Cancel" add the "rotation offset" GameObject from the TeleportController GameObject and do GameObject.SetActive (false) - Also disable it by default. - Next in de DialRotator class in the method SelectedBy replace the line "directInteractor.hideControllerOnSelect = true;" with "directInteractor.xrController.hideControllerModel = true;" I'm not able to add screenshots here but I hope it is clear :-)
For anyone whose dial is "not responding" to grabs, you MUST have an "XR Direct Interactor" and a collider that is a trigger on the hand you are grabbing with.
Great video! Students in my classes will be using this as part of their VR dev training!
Good job
One of the BEST tutorials I found out here
Can't underestimate a person that uses namespaces LOL
Easily one of the best VR Channels for Unity on YT.
Thanks Rick!
Thank you for a great video! I'm shocked it doesn't have more views. Keep up the great work!
Very useful tut, I hope to see your concepts of tutorial about Shooting/Projectiles with VR new input system soon, thx again mate.
Just found this channel, amazing stuff. Also nice to see how you set up your code, I've been figuring out how to do lots of stuff, but all my code is an absolute mess. Keep up the videos!
Very nice model you made there. And thanks for showing how to make a dummy hand with a pose. Going to try this one out too.
Fantastic! It was really easy to extend your code to allow for minimum and maximum values, looking for specific values, etc. Great for puzzle games!
Do you think you could do a follow-up for levers and sliders?
That's the plan, I'm hoping to do a VR puzzle game series in the near future so that would be great to slot into that course
@@UnityVR Awesome. Levers especially. I've got one working that utilizes Hinge Joints, but that means that it's nearly impossible to have it be attached to another grabbable like I had the dial. An unfortunate limitation.
Perhaps you'll have a more elegant solution in mind!
How are you implementing Min / Max values .
I am trying mathf.clamp on a Rotation float inside RotateDialClockwise().
I can clamp clock wise rotation between eg : 0 - 90f
but cant work out how to clamp anti clockwise between 270 - 360
Im not sure that this is the best solution anyway .
Any advise would be greatly appreciated .
Cool, thanks a lot for all those tutorials :D
Great video. Thanks
Hi Daniel I know this is an old ish video and I am enjoying your videos and apply them to my project but I do have a question as I have only just started is it possible to use this to move through an animation for example if I turn a dial clock wise it will go forward a couple of seconds every 25 degrees and the same backwards when you turn it anti-clockwise just to put this in to context I am making a machine that when you turn a dial it changes the position of a part
Thanks for another great video! I have a slight problem as my dial spins constantly as soon as I rotate just a little to either side. I believe I am using a newer version so I guess something might have changed...
Would it be possible to have dials be attached to other grabbable objects such as a dial that is attached to a remote control that you can grab with the other hand?
EDIT: It turns out that, with this system there is no reason to use XRGrabInteractable at all! You can just as easily use XRSimpleInteractable instead, allowing players to mount the dial to other grabbables, moving objects, etc.!
cool, I meant to do that.. honest. :)
Thanks for the clear concise run through.
Would it be possible to update Rotator.cs to deal with updated XR Framework 2.0 , as it seems that certain features are now depreciated. ( ? I think ? )
my error is : when switchCollider is entered
NullReferenceException: Object reference not set to an instance of an object
LevelUP.Dial.Rotator.GrabbedBy (UnityEngine.XR.Interaction.Toolkit.SelectEnterEventArgs arg0) (at Assets/LevelUpTutorialAssets/Scripts/Dials/Rotator.cs:42)
is below now broken ? ( line 42 on Rotator.cs)
interactor = GetComponent().selectingInteractor;
interactor.GetComponent().hideControllerOnSelect = true;
I downloaded the code from source ,just to test the functionality. With intention of replicating.
would love to get this working .
Cheers
SOLVED: As usual my fault . User error. The fact not being able reference the interactor, because I was using RAY interactor.
i was attempting this because Direct Interactor was not interacting in any way at all. At least with ray i was getting a collision response.
You have to use Direct Interactor ( as stated ) BUT it also needs a Trigger Collider.
Thanks for your tutorial 🔥🔥,but i found a problem, when i rotate, the dial is out of its parent, is there any solution for that.... i hope you reply🙌🙌 thanks
Great tutorial!, hmm how would you do buttons, i tried to do the Vr versions with hinge joints, but im then forced to have an other collider or object to push em
dont want to use OnTriggerEnter/Exit/Stay? You could get the bounds and move the button accordingly within the range in the OnTriggerStay method. Thats how Ive made most of my VR UI. Most methods require the use of physics though unfortunately.
Hi.. a video is on the way.. just looking to see if physics is the way to go or do something in script..
@@UnityVR have been looking at the escaperoom exaple button, but it behaves a bit weirdly, they are using sweeptest to determine if some rigidbody is close, but it seems to trigger far away from the hand :)
I get errors in this lines, grabInteractor.selectEntered.AddListener(GrabbedBy);
grabInteractor.selectExited.AddListener(GrabEnd); does the script work in 2019.4 version?
Hi, yeah it should work fine. Feel free to copy/past your script I can take a quick scan through..
@@UnityVR
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.XR.Interaction.Toolkit;
public class Rotator : MonoBehaviour
{
[SerializeField] Transform linkedDial, dial2, DIALE3;
[SerializeField] private int snapRotationAmount = 25;
[SerializeField] private float angleTolerance;
[SerializeField] private GameObject RighthandModel;
[SerializeField] private GameObject LefthandModel;
[SerializeField] bool shouldUseDummyHands;
public MagnetismFaraday magnetismFaraday;
private XRBaseInteractor interactor;
private float startAngle;
private bool requiresStartAngle = true;
private bool shouldGetHandRotation = false;
public float rotza, ROTZAB;
private XRGrabInteractable grabInteractor => GetComponent();
private void OnEnable()
{
grabInteractor.onSelectEntered.AddListener(GrabbedBy);
grabInteractor.onSelectExited.AddListener(GrabEnd);
}
private void OnDisable()
{
grabInteractor.onSelectEntered.RemoveListener(GrabbedBy);
grabInteractor.onSelectExited.RemoveListener(GrabEnd);
}
private void GrabEnd(XRBaseInteractor arg0)
{
shouldGetHandRotation = false;
requiresStartAngle = true;
HandModelVisibility(false);
}
private void GrabbedBy(XRBaseInteractor arg0)
{
interactor = GetComponent().selectingInteractor;
interactor.GetComponent().hideControllerOnSelect = true;
shouldGetHandRotation = true;
startAngle = 0f;
HandModelVisibility(true);
}
private void HandModelVisibility(bool visibilityState)
{
if (!shouldUseDummyHands)
return;
if (interactor.CompareTag("RightHand"))
RighthandModel.SetActive(visibilityState);
else
LefthandModel.SetActive(visibilityState);
}
void Update()
{
if (shouldGetHandRotation)
{
var rotationAngle = GetInteractorRotation(); //gets the current controller angle
GetRotationDistance(rotationAngle);
}
DialCalculate();
}
public float GetInteractorRotation() => interactor.GetComponent().eulerAngles.z;
#region TheMath!
private void GetRotationDistance(float currentAngle)
{
if (!requiresStartAngle)
{
var angleDifference = Mathf.Abs(startAngle - currentAngle);
if (angleDifference > angleTolerance)
{
if (angleDifference > 270f) //checking to see if the user has gone from 0-360 - a very tiny movement but will trigger the angletolerance
{
float angleCheck;
if (startAngle < currentAngle)
{
angleCheck = CheckAngle(currentAngle, startAngle);
if (angleCheck < angleTolerance)
return;
else
{
RotateDialClockwise();
startAngle = currentAngle;
}
}
else if (startAngle > currentAngle)
{
angleCheck = CheckAngle(currentAngle, startAngle);
if (angleCheck < angleTolerance)
return;
else
{
RotateDialAntiClockwise();
startAngle = currentAngle;
}
}
}
else
{
if (startAngle < currentAngle)
{
RotateDialAntiClockwise();
startAngle = currentAngle;
}
else if (startAngle > currentAngle)
{
RotateDialClockwise();
startAngle = currentAngle;
}
}
}
}
else
{
requiresStartAngle = false;
startAngle = currentAngle;
}
}
#endregion
private float CheckAngle(float currentAngle, float startAngle) => (360f - currentAngle) + startAngle;
private void RotateDialClockwise()
{
linkedDial.localEulerAngles = new Vector3(linkedDial.localEulerAngles.x,
linkedDial.localEulerAngles.y,
linkedDial.localEulerAngles.z + snapRotationAmount);
if (TryGetComponent(out IDial dial))
dial.DialChanged(linkedDial.localEulerAngles.z);
}
private void RotateDialAntiClockwise()
{
linkedDial.localEulerAngles = new Vector3(linkedDial.localEulerAngles.x,
linkedDial.localEulerAngles.y,
linkedDial.localEulerAngles.z - snapRotationAmount);
if(TryGetComponent(out IDial dial))
dial.DialChanged(linkedDial.localEulerAngles.z);
}
void DialCalculate()
{
Vector2 dir = dial2.position - DIALE3.position;
float angle = Mathf.Atan2 (dir.y, dir.x) * Mathf.Rad2Deg;
angle = (angle = 315) ? (angle - 360) : angle) + 45;
//Debug.Log(dialvalue);
Debug.Log(angle);
rotza = angle;
}
}
@@UnityVR
I edited it to this and it worked in 2019.4 grabInteractor.onSelectEntered.RemoveListener(GrabbedBy);
grabInteractor.onSelectExited.RemoveListener(GrabEnd);
} thanks for your tutorials
First: great tutorials! Thanks for that. I have one problem. I don't know why but the controller (hand) is not hiding on select. So I see two hands if I interact with the dial. I've tries everyting and checked all my settings but I can't find the problem. I expect it has something to do with the newer version of the XR Interaction Toolkit.
Am I the only one with this problem? Or has someone have the same problem and has a solution? Thanks :-)
Hi Henk, you could use the package manager and see if you are using the same version as XR interaction toolkit as me? if so does the dial turn?
@@UnityVR I'm using version 1.0.0-pre.3 and when I select "Hide Controller On Select" i still see the hand for all the interactions. The dial turn works but I see 2 hands when I try it. I also tried the Room-Scale XR Rig (provided by Unity) and than the hand will hide like it should. Also I tried deactivating de Left and Right Teleport Controller entirely and than it works also like expected.
Ok, I've fixed it. For everybody who is interested this is what I did (for both hands):
- in the "Teleport Controller / On Teleport Activate" add the "rotation offset" GameObject from the TeleportController GameObject and do GameObject.SetActive (true)
- in the "Teleport Controller / On Teleport Cancel" add the "rotation offset" GameObject from the TeleportController GameObject and do GameObject.SetActive (false)
- Also disable it by default.
- Next in de DialRotator class in the method SelectedBy replace the line "directInteractor.hideControllerOnSelect = true;"
with "directInteractor.xrController.hideControllerModel = true;"
I'm not able to add screenshots here but I hope it is clear :-)
@@HenkJanBaard Well done for fixing it and thank you for posting the solution!
Hi :) this is amazing!! Would I be able to use this with Occulus VR, has anyone tried please?
si, en las oculus quest 2