Creating a VR Menu - 2019.2
Tutorial
·
Beginner
·
+10XP
·
30 mins
·
(129)
Unity Technologies

In this tutorial, you’ll set up a VR Menu in World space and configure it so users can interact with it accordingly. By the end, you will be able to set the color of a panel by pointing at a button and pulling the trigger on the handset.
Languages available:
1. Create a WorldSpace Canvas
1. Right-click in the Hierarchy window and navigate to 3D Object > Cube (Figure 01). Click the gear widget at the top right of the Inspector window for the cube and choose Reset. This should put your cube at the origin and set the scale to 1,1,1.

Figure 01: Creating a cube primitive
2. Next, right-click in the Hierarchy window again and select UI > Canvas (Figure 02).

Figure 02: Creating the Canvas
3. Select the Canvas and, in the Canvas component in the Inspector, change the Render Mode to World Space (Figure 03).

Figure 03: Setting Canvas to World Space
4. Make the Canvas a child of the cube primitive (Figure 04).

Figure 04: Making the Canvas a child of the cube
5. Then, click the gear icon on the Rect Transform component of the Canvas and click Reset. Change the Pos X, Pos Y and, Pos Z values to .1, 3.8, 0, respectively, and set the width to 15 and the height to 5 (Figure 05).

Figure 05: Setting the Rect Transform
6. Right-click on the Canvas in the Hierarchy window and select UI > Panel. Set the Source Image on the Image component to None and change the color on the color picker to a color you like. This tutorial has it set to a light grey (Figure 06).

Figure 06: The Image component on the Panel
7. Your Game view should now look something like the image below (Figure 07).

Figure 07: The Game view
8. Right-click on the panel in the Hierarchy window and select UI > Button. Rename the new button to "red_btn". Expand the button in the Hierarchy and select the text GameObject. In the Inspector window on the Text component, enter RED in all caps and select Best Fit in the Paragraph section (Figure 08).

Figure 08: The Text component settings
9. Set the button’s width to 100 and the height to 33, then press the R key to select the scale tool. Scale the button down until it fits within the Canvas. Next, select the Rect Transform tool, and move the button into the left third of the Canvas (Figure 09).

Figure 09: The button placed within the panel
10. Set the button as a child of the panel by clicking and dragging it into the panel in the Hierarchy window. With the button selected, press CTRL+D to duplicate it (CMD+D on a Mac). Select the Rect Transform tool and move the button to the center of the panel. Repeat this process one more time to create a third button and put it in the right third of the panel. Rename the new buttons to be "blue_btn" and "green_btn". Change the text on the buttons to be different colors. For this tutorial, use RED, BLUE, and GREEN (Figure 10).

Figure 10: The finished menu view
2. Create a Material for the cube
1. Right-click in the Project window and select Create > Material (Figure 11).

Figure 11: Creating a Material
2. Name the Material what you would like. In this tutorial, we’ll call it Cube_Mat. Set the color to black and apply the Material to the cube.
3. Configuring hand tracking
1. First you will need to make sure you have OpenVR enabled. Click on Window > Package Manager. In the Package Manager, scroll to OpenVR and if it’s not installed, install it. If it’s installed, verify that it is up to date (Figure 12).

Figure 12 - Installing Open VR
2. Next, go to Edit > Project Settings and click on the Player tab. Scroll to the bottom and make sure Virtual Reality Supported is checked and that OpenVR is added under Virtual Reality SDKs. If it’s not, click on the plus sign and select OpenVR (Figure 13).

Figure 13: Enabling OpenVR
3. Create a capsule primitive and in its Inspector view, click the gear widget and choose Reset. Press W to select the move tool and move the capsule a little bit to the right and below the cube. This will be your “hand,” or VR Motion Controller.
4. Next, you will need to install and enable XR Legacy Input Helpers from the Package Manager. If you don’t have that window open from before, go to Window > Package Manager, scroll to the bottom of the list, and install XR Legacy Input Helpers (Figure 14).

Figure 14: Installing XR Legacy Input Helpers
5. Next, click Add Component in the Inspector, search for Tracked Pose Driver and add it to the capsule (Figure 15).

Figure 15: Adding the Tracked Pose Driver
6. This driver will track the position of your XR controller. It can be used to track other items, such as your HMD or generic devices, but for this purpose, you will want to set it to track Generic XR Controller (Figure 16).

Figure 16: Tracking the Generic XR Controller
7. Once you’ve set this, set the Pose Source to the controller you’d like to be tracked. For this tutorial, we’ll be tracking the right controller.
4. LineRenderers for pointing
Now we will set up a way to track where your hand is pointing and get the UI to interact with our controller using Raycasts, Colliders, and a LineRenderer.
1. Add a LineRenderer Component to the capsule you are using for hand tracking.
2. Create a new script by right-clicking in the Project window and choosing Create > C# Script. Name the script LineRendererSettings.
3. Add the following code to the script.
This code sets the initial points to the LineRenderer starting at the position of the capsule and ending 20 units away, in the Z-direction (forward). Because your hand is being tracked, the LineRenderer will not be centered on your capsule and will not follow your hand. We’ll set that up next.
Now we need to get the LineRenderer to stay aligned with our Raycast so that our user knows which way they are pointing.
1. Add the following code to the LineRenderSetttings script:
2. In the Update() method, add:
3. Finally, make sure that Use World Space is unchecked and that Alignment is set to View on your LineRenderer Component (Figure 17).

Figure 17: Setting the Line Renderer
Now the LineRenderer should follow the ray you are casting. You can now create a Material for the LineRenderer. In this tutorial, the Material will have an Albedo color of green.
5. Interacting with the UI
Now that you’ve set up a way to track where you’re pointing, it’s time to configure interacting with the UI.
1. Add a Box Collider to each of the buttons and set the X and Y dimensions to match the button size. Set the Z to .1 (Figure 18).

Figure 18: Box Collider settings
You are already changing the LineRenderer length if it collides with a piece of the UI. Now let’s change our LineRenderer color so users will know they’ve hit a button.
1. Inside of the if (Physics.Raycast(ray, out hit, layerMask)) block, add:
2. Next in the else block of the same if statement, add:
3. Finally, at the bottom of the AlignLineRenderer() method, add:
Now let’s make something happen when the user clicks on the button.
1. On the top of your using statements, add using UnityEngine.UI (Figure 19).

Figure 19: Using UnityEngine.UI
2. Declare a new public GameObject variable called “panel”, a new Image variable called “img”, and a Button variable called “btn” (Figure 20).

Figure 20: Declaring your image, panel and button
3. Left-click and drag the panel from your Hierarchy window into the slot on the LineRendererSettings script on your Capsule (Figure 21).

Figure 21: Adding the panel to your component
4. Back in the LineRendererSettings script inside the Start() method, add the following:
5. Inside of the AlignLineRenderer() method inside the if(raycast) block, add:
Now we can set the background panel image according to the button that is clicked. But, first, we will need a method to call when the buttons are clicked.
1. Declare a new method called ColorChangeOnClick()(Figure 22):

Figure 22: Declare ColorChangeOnClick() method
2. Inside that method, add the following code (Figure 23):

Figure 23: Logic for ColorChangeOnClick()
3. Now, let’s modify our AlignLineRenderer(Renderer rend) method to return a boolean if it hits a button. That way, we can decide when to invoke the button.
4. Change the return type from void to bool(Figure 24):

Figure 24: public bool AlignLineRenderer
5. At the beginning of the AlignLineRenderer() method, declare a new boolean variable called isHit and set it to false.
6. Inside the if(Physics.Raycast) block, after the code you’ve already added, add:
7. Inside the else{} block add hitBtn = false; (Figure 25).

Figure 25: Finished AlignLineRenderer() method
6. Fire the event when your user points and clicks
Now you will configure the input from your VR controller and set the events up.
1. Click on red_btn in the Hierarchy. In the Inspector, navigate to the OnClick() event and click the + symbol.
2. Left-click and drag your Capsule from the Hierarchy window into the object slot in the newly created event (Figure 26).

Figure 26: Adding the Capsule to OnClick()
3. Next, click the drop-down to the right of the runtime Only drop-down and navigate to your LineRendererSettings component. When that expands, select the ChangeColorOnClick() method. This will make the method fire when the OnClick() event is called (Figure 27).

Figure 27: Setting ColorChangeOnClick()
4. Repeat this process with the other two buttons.
Now that your buttons are set up, all you need to do is have something listen for when a button is hit by your Raycast and if the trigger on your VR Controller is pulled.
- Inside your Update() method, add the following code:
This code will call the OnClick() eEvent hHandler of the button the user has targeted with the controller. If they pull the trigger (which you will verify is mapped to the Submit Axis), it will set the color of the panel to match the button.
Click on Edit > Project Settings and select Input. Look for the Item named Submit. Click the arrow to the left of Submit and make sure the Alt Positive Button option says joystick button 15. This will register the right-hand controller trigger to the Submit Axis (Figure 28).

Figure 28: Setting the Submit Alt Positive Button
And that’s it! When you hit the Play button with your HMD connected, you should be able to point at a button and pull the trigger to change the color of the panel. You can use this method to fire off other events when users interact with menus. You may want to display information on the object they click, change a game setting, or even give the player power-ups.