The Room: A Unity Step-by-Step Tutorial¶
This tutorial will guide you on starting a project in Unity from scratch. Once you are done, you will have created a basic room with some simple functionalities and scripts.
Provided Files¶
We provide some of the materials for you to download and use:
Creating a Unity Project¶
Create a
Project
in Unity. To create a new project, click the New Project
button on the top right. If you are using university computers, pay attention where the project is saved. All saves on PCs are deleted when they are rebooted. We will use the 3D template:
Get acquainted with Unity’s basic features and the interface: Interface Tutorial.
Part 1. Setting Up the Room and Unity UI Basics¶
1.1 The Room¶
Build a cubic room out of six planes. Make sure to orient these planes so the visible sides face inwards, and ensure that the player cannot walk through any of them. The room should be 15x15x15 Unity units (aka meters). Create a plane:
GameObject → 3D Object → Plane.
Unity’s default plane size is 10×10(X×Z) units. In order to make your room 15 units wide, you have to scale the plane. On the right side (in the default editor layout) you will find the
Inspector
window. This window provides details about the currently selected object. Select the plane in the Scene
view, and the Inspector
will fill with information and settings for said plane. Find the Scale
option, and set the X
and Z
values to 1.5 to make your plane 15 units wide and long. Build the rest of the walls by adding new planes or duplicating the existing and adjusting scale, position, and rotation. The plane has no thickness, so the value in Y can be any positive integer and remember your plane is now 15 units/meters wide.Note: The plane also rotated its axes, when you adjust rotation so the local axes change. Make sure to account for that when rotating and moving objects!
Note: By default, your scene has a directional light in it, which illuminates your entire scene from a specified angle, from very far away, much like the sun. You’ll notice that your planes do not block this light. That’s because planes only block light (and render) from one side. Make sure that in your room, all six planes face inwards, and bear this in mind when creating objects in Unity in the future! For now, just delete the directional light. You will add more lights later.
1.2 Player Controller in VR¶
Note: If you do not yet have access to an HMD, you should still be able to follow these steps, you will just be unable to test the results properly.
To get started with setting up VR for your project, open
Package Manager
(right next to Asset Store
as seen in the screenshot above). In Package Manager
, look for packages from Unity Registry
(top left in the window), search for OpenXR
, select it and click Install
. See screenshot below for how to navigate the Package Manager
window. In addition, import the controller sample, which will appear in the window after installation. That will allow you to test your controllers, see how they work and also use it as an example.You may then see a warning about an interaction profile. Next, we should navigate to
Edit → Project Settings → XR Plug-in Management
and select OpenXR
. Although you probably have an Oculus device, OpenXR
is a more universal solution, allowing your project to run on other devices as well, so we will use that. After that, select
OpenXR
below XR Plug-in Management
and add an interaction profile. For most of you, Oculus Touch is the correct profile, so add that. If you have different controllers, choose a suitable option. Note that even when a specific profile is selected, many actions are shared between different controllers, so it will work with different controllers too.After that, all the packages and settings should be in order! Try opening the sample scene that was imported earlier (Assets/Samples/OpenXR Plugin/{version number}/Controller/ControllerSample.unity) and run it. If everything is working correctly, you should see the scene in your HMD and your controller inputs should be visible on screen. There should even be vibration.
PlayerRig
is the object in the scene where the tracking and inputs are set up. We will go into more detail later, but for now you may wish to look at what it consists of.The easiest way to set this up for your own scene is to create a prefab of the
PlayerRig
by clicking and dragging it to your Project → Assets
in the Unity window. You may wish to remove some of the unnecessary components, but for now it’s fine to leave them there. Place the prefab into your scene, at (0,1,0), and delete the main camera
object.1.3 Lighting¶
Create a point light
GameObject → Light → Point Light
, and place it at (0,15,0). The Inspector
tab should have a Light
component like below:Of primary importance are the range (the radius of your light), color, and intensity values. Set the shadow type to soft shadows, and the mode to Realtime. Set your range and intensity so that your room is brightly lit.
We recommend reading the Unity manuals for general lighting, shadows, and lighting modes. In later homework, and your course project, these settings can impact performance significantly.
1.4 Planet and Moon¶
Create two spheres
GameObject → 3D → Sphere
. Scale the first sphere to 2 in all directions, and place it in the center of your room. In the Hierarchy
view, drag the second sphere onto the first. The result should look like this:Now, the second sphere is a child of the first sphere. When you change the position, rotation, or size of the parent sphere, its child will also undergo the same movement, rotation, or scaling. The (0,0,0) origin position of the child is now its parent’s position, not the global (0,0,0) origin. That is, the child’s position is an offset from the parent’s position. Finally, if the parent rotates, then the child will rotate about its parent’s axes, not its own axes (this will make more sense later). See the Unity hierarchy manual for more information.
Set the position of the child sphere to be (2,0,0), which is four units from the parent sphere on the X-axis. For why this is, think about the scaling of the parent sphere.
1.5 Text¶
Check out the Unity tutorial on Creating Worldspace UIs. Create a canvas
GameObject → UI → Canvas
and then create a text object under it GameObject → UI → Text
. If you create a text object directly, it will be parented under an existing canvas, which may not be desired since our PlayerRig
prefab uses its own canvases. The canvas should look like this in the Inspector
tab:First, change the
Render Mode
from Screen Space - Overlay, to World Space. This changes the canvas from a UI element glued to the camera, to an object that is stationary in the world. Traditional UIs do not work well in VR, and we strongly discourage sticking any UI elements to the camera in your future Assignments. Always attach UI elements to something in the world (see this).Now that the canvas is a world space object, we can make it a more reasonable size. However, since the
Rect Transform
’s width and height are in units of pixels, not world units, we must first set the resolution of the canvas. Set the width and height to 1000 (that is 1000×1000 pixels). Now, shrink the canvas by setting the scale. Multiplying the canvas width and height by the scale factors gives the actual size of the canvas in world space. For example, since we set the canvas to be of size 1000×1000 pixels, using scaling factors of 0.01 would make the canvas 1000∗0.01=10 units large in world space. Adjust your text’s Rect Transform (position and with/height) to be the same as on the parent canvas, but leave the scale as it is, 1. Now, you can place your canvas against one of the walls.Offset it a small amount (like, 0.001) off of the wall it is against to avoid Z-fighting, which happens when two objects have the same depth, and Unity can’t figure out which one to render. Below is an example of Z-fighting:
Now, you can set your text color, size, font, width, whether it wraps or overflows, etc. You can check how your project looks in VR by just clicking play on top of your
Scene
view. Later when we start scripting, make sure your text has the controls for your game. Make sure the text is big enough for us to read. If the text appears blurry or jagged, then increase the width and height of the canvas and text (to increase the resolution), and scale them down further.
1.6 Material¶
Read the Unity materials, shaders and textures manual, focusing mainly on the materials, for now. A base texture (tile.png), and a normal map (the weird purplish image tile-normal.png) can be found from the Provided Files (materials.zip). To create a material, go to
Assets → Create → Material
.This will generate a default material, which should show up in the
Inspector
tab like so:Drag the tile.png image to the box labeled
Albedo
. Now, drag this material from the Assets
folder onto one of your walls in the Scene
view. It probably doesn’t look too good. Don’t worry, it’ll get better. Drag the tile-normal.png image to the box labeled Normal Map
. Notice how it changes the visual perception of the material. A normal map is a trick used to give the illusion of depth on a flat surface, by telling the engine to reflect light as if there were these little bumps and pits in the material. Apply this material to a wall by dragging it onto a wall.Create a new material, called Wall 2, apply the same albedo and normal maps as you just did for Wall 1, and apply it to a different wall. Right below the
Secondary Maps
subheading is the Tiling
option, which has an option for X
and Y
. Tiling causes a material to repeat itself on the same object, rather than covering the whole thing. So, changing tiling X
to 2, means that the material will repeat once, and show up twice, in the X
direction on the wall. Play with the tiling until you like the look of it. Below is an example of non tiled and tiled walls side by side.In the
Inspector
tab, right below the Albedo
option, there are Metallic
and Smoothness
sliders. Play around with these, and see how they affect the material. The Metallic
slider adjusts the reflections, and Smoothness
helps to enhance or subdue the normal map. Modify the metallicity and smoothness of the two wall materials so that they are clearly visually different.Finally, create a material that has no albedo or normal map. Next to the
Albedo
option there is a small color box. Since this material has no albedo, the material will be this flat reflection color. Try and see what happens when you change the color of a material with an albedo. Apply this flat color onto a third wall in the room.1.7 Adding Skybox¶
Follow the instructions in the Unity skybox manual to set up the skybox. Since the room is currently enclosed, you won’t be able to see the skybox from the room. We will remedy that in the scripting section below.
The skybox is from mgsvevo.
Part 2. Scripting in C#¶
2.1 Basic Scripting¶
Unity scripts use the C# language. If you are unfamiliar with programming, you can check out this C# tutorial. You’ll only need the basics of objects, classes, and variables for now.
We recommend reading the Unity scripts manual and the script object API.
Unity’s Scripting API Reference is a useful source of information for when you are scripting new objects. For the first script, we will detail the functions that we recommend, but for the others, we expect that you will refer to the API reference if needed.
If you have access to VR HMD and controllers, use those controllers as the input device. You may test the following scripts with keyboard inputs until you get access to VR hardware. However, the returned assignment should function with the motion controllers of a VR device.
For testing without VR hardware, you may also find it useful to use the
Scene
view. When you run the scene in the Unity editor, the view defaults to Game
, but it can be switched to Scene
right after, allowing you to move the rig, simulate movement, or otherwise manipulate the scene. You can also monitor the whole scene this way and ensure everything is functioning as intended.Some documentation about input systems is linked below. However, you may find it sufficient to simply take example from the controller sample scene.
2.2 Quit Key¶
Create a new script using the
Assets
menu (Create → C# script
). To attach the script to an object, select the object, then drag the script from the Assets
tab to the Inspector
tab. (Alternatively, you can create and attach a script in one step using Add Component → New Script
.) For this script, the exact object attached is unimportant.When a Unity script is attached to a
GameObject
, that script will run when the game is started. Furthermore, the this
reference in the script will refer to the object to which the script is attached.By mimicking the input code in the controller sample scene, we can make it something like this:
In addition, remember to set the desired action in the Unity editor. The controller sample should come with all the necessary actions to use all the input options of your controllers, and you can find and select these by pressing the circle icon on the right, but if you want to add other actions or edit them in some way, you can find the input actions file by clicking on the text after selecting an action, or you could just right click on the
Project Assets
window, Create →Input Actions
.This documentation may also help you understand what action corresponds to what button.
Application.Quit()
quits a Unity application, but it will not stop a game running in the editor. Thus, we use an #if and a Unity-specific preprocessor directive that adjusts its behavior depending on whether the project is within the editor, or a standalone executable.2.3 Light Switch¶
Make a script and attach it to the point light. Our first step is to get the Light component of our point light GameObject. Read the Controlling GameObjects using Components tutorial, then add these lines to your script:
The Start function runs as the game initially starts. This saves a reference to the Light component for later use.
Alternatively, you can declare public
GameObject
variables. Save your script, then navigate to the script in the Inspector
pane. The variable will show up in the Inspector
pane, and you can assign GameObject
to it by dragging them from the hierarchy tab into the variable slot! This works similarly for other variable types. You can read more about this in the Variables and the Inspector tutorial.To change the light, write something similar to the following, but remember to do it according to the input system you are using rather than just copying the code below.
For the actual light color, you can either create a new color using the
new Color(red, green, blue)
constructor, or one of the predefined colors. How you change the light is up to you, but pressing the controller button you designate must visibly change the light color.2.4 Orbiting Moon¶
Make the moon orbit the planet. The easiest way to do this is to have the planet object constantly rotate. Since the moon object is a child of the planet object, it will also rotate around the planet. You can control the rotation and position of a GameObject with the transform object variable, an instance of the aptly named Transform class. Use the functions of this class to rotate the planet system around the Y-axis. Keep in mind that the Update function runs every frame, but frames often vary in real time length. Thus, using static rotation amounts with the Transform class will make the apparent rotation amount depend on framerate. This is generally not desirable. To use real time frame times instead, use the Time.deltaTime variable.
2.4.1 Break Out¶
Set up a button on the controllers to switch the player’s position between an external viewing point and the room.
Like any
GameObject
, the player object has a Transform
. With that in mind, make a script that switches the player between a room and a new external viewing point, e.g. a small new plane a moderate distance from the room. The player should still start within the room. Pressing the button for the first time must move the player to the external viewing point. After that, pressing the button must alternate between the two locations.You can control the rotation and position of a
GameObject
with the Transform
object variable, an instance of the aptly named Transform class. Use the functions of this class to rotate the planet system around the Y-axis.Part 3. A More Interesting Room¶
Instead of the cube room we laid out above, use a modeling tool to create more complicated room geometry, like a curved roof, slanted windows, multiple levels, et cetera. Please write down what you created. Your creation still needs to have the other features of the room we described above.
Blender is a free and powerful 3D modeling software, but you may also use something else if you prefer.
The default Unity modeling tools are extremely limited, so we highly recommend you familiarize yourself with another tool. It will assist greatly in your final project. You can use the room as a basis of your course project.
Authors¶
Nathaniel Myren, Shantanu Tulshibagwale, and Elmeri Uotila.
Give feedback on this content
Comments about this material