Create Your First VRChat World

Video version: This is the script of a video tutorial series about how to create your first VRChat World using a Unity-only workflow. This is a project-based course which will end with having a made a unique room and understanding the basics of world creation, such as using Unity and the VRChat SDK, constructing unique geometry with Probuilder, materials and PBR textures, detailed lighting, the asset store and external models and prefabs, World Space UI, Udon, pickupabbles, and Quest compatibility.

Introduction to Unity and VRChat Creator Companion

Have you ever wanted to make your own VRChat world but never knew how to start?

Creating an interior in Unity isn’t as hard as you might think!

This beginner course covers everything one should need to know when building a scene, including many best practices. It will be accessible to everyone, including those who have never touched 3D before. We will only be using one software: Unity; this way, you will be able to create scenes fast and efficiently without having to worry about learning or exporting from completely different software such as Blender.

First you have to install the Unity hub, which makes it easy to work with multiple versions of Unity; so when it inevitably updates, the hub makes it easier to download new versions and upgrade or migrate projects. It is also a requirement for creating VRChat projects.

If you’re just using Unity without VRChat, it’s preferable to download the latest LTS version of Unity. Otherwise, skip that and download the VRChat Creator Companion (either the download page after you login to the VRChat website or from the direct link in the description), which will install the correct version of Unity for you if you have the Unity Hub installed.

In the Unity Hub you’ll need to log into your Unity account, or create one if you don’t have one already. You need a license to use the software but the personal license is free and perpetual. If you’re having trouble with this part, then in the preferences of Unity Hub go to Licenses to fix it. I only have a professional license because I’m using the student version of Unity.

If you’re not creating a VRChat project go ahead and create a new Unity project. URP is preferable for most people starting new projects but this series will cover the Built-in render pipeline (because that’s what VRChat uses) which only has small differences, mostly in the materials and shaders. I’ll do my best to point out these differences when they come up. I would not recommend starting with the high definition render pipeline because that one is significantly more complex.

If you’re making a VRChat project, the first thing you need is (not a Steam or Oculus account but) a VRChat account of at least New User rank, the blue one, otherwise you won’t be able to upload anything!

After you’ve gotten the Unity Hub and Creator Companion installed, create a new UdonSharp project. This is a world project that allows for C# scripts that use VRChat’s Udon programming language. Even if you’re not gonna touch it yourself, it will allow you to import a bunch of cool toys the community has created; I'll touch on that in a future video.

Here’s a tip: I recommend putting all of your Unity projects in a folder on your larger hard drive if you have multiple, because they can get pretty big!

Once all that is finished, Unity will take a bit to set everything up and then it will open! You should now see the default layout of Unity when you first create a project.

If you want to change Unity between light and dark modes, you can go to Edit>Preferences>General>Editor Theme.

The largest and most prominent window is the scene view; this is a 3D view of your Unity scene. You can use the mouse wheel to zoom in and out. You can use the middle mouse button to pan (or press Q to use the left mouse button instead), and if you hold ALT and left click you can pivot. You can look around by holding the right mouse button and moving your mouse, and while holding, you can also navigate the scene by using the WASD keys, as well as E and Q for ascending and descending.

There should be two objects in the default scene. You can see them in the Hierarchy tab, which is on the left side of the screen by default. If you click on the Main Camera, it will highlight in the editor, a 3-axis gizmo will appear on the object in the scene tab, and information will appear in the rightmost tab, the Inspector. The inspector shows all the information of an object, and each collapsable section is called a component. Every object will have a transform component, which denotes its X Y and Z position, rotation and scale. If you edit the value in the Inspector, the object updates in the Scene view, and vice versa.

Understanding gameobjects is key to understanding Unity. In Unity, everything is a gameobject, and every gameobject can be filled with components to make things happen. Put another way, gameobjects are essentially just containers for different components which can actually do things.
For example, the main camera is not a camera object; it is a gameobject with a camera component. The directional light is not a light object; it is a gameobject with a light component. A character in a video game is not a character object but a gameobject with a skinned mesh renderer component and a character controller component and a bunch of other components and scripts that make it behave like a playable video game character.
Only when you start to think in components can you truly master Unity.

At the bottom of the screen should be the Project view, which shows all of the game assets in the project, many of which can be dragged into the scene. 

Unity scenes are like separate levels or worlds: we can create multiple different scenes in a single Unity project but a VRChat world is confined to a single scene.

You can rearrange these panels however you want. For the sake of conformity and ease of learning, I will be keeping the default layout for this series unless I explicitly open a new tab required for the course, which I will make clear. If you ever want to reset to the default layout, you can simply click the dropdown in the top right corner which should say Layout and select Default, or Window>Layouts>Default.

Now we will set up a test scene. First, we need to add a ground plane for the player to stand on. To add an object, go to the Hierarchy, right click and select 3D object>Plane (alternatively you can use the GameObject menu up top). Press F in the Scene tab with the object selected to snap to it. By default, there should be a gizmo on it in the center of the object that has 3 arrows; you can change between the gizmos with the keys W, E, R, T and Y. We want this plane to be in the center of our scene, also called the origin. To do this, make sure the plane is selected, go to the Inspector, and under the Transform component, click the 3 vertical dots, and click reset. This will reset the XYZ position and rotation of the object to 0,0,0 and the scale to 1,1,1.

If you are just making an environment in Unity and not VRChat, you can import and drag in your character controller of choice, such as Unity’s first person controller template. 

The rest of this lesson will be to ensure that it’s possible to upload working worlds to VRChat. 

If you made this project with the VRChat creator companion then you will see a menu in the menu bar called VRChat SDK. Before touching that go to the Project tab, instead of assets, click right below it where it says “packages”, click the search bar and type “VRCWorld”. 
Drag VRCWorld.prefab into the Hierarchy. Reset the transform to the world origin if it isn’t there already.

Now, go to VRChat SDK>Show Control Panel, and a new window should pop up, which you can dock if you like. Log in and then select the build tab. 

Under Local Testing, check force non VR. VRChat should launch, and if everything goes well then you should spawn in the scene on top of the plane!

I would recommend closing the VRCSDK window when not in use, as it has been known to slow Unity down. If the window is undocked, you can close it by clicking the x at the top right corner, or you can right click on the tab and select Close Tab.

VRWorldToolkit gives us a bunch of tools to help make our world more optimized and ensure it isn’t broken; import it from the VRChat Creator Companion.

If you need help throughout this series, I would recommend asking in Unity’s forums or the official VRChat Discord as you’re way more likely to get a response (if you ask nicely and post relevant screenshots). Besides, the comments section isn’t designed for answering technical questions.

That’s it for this lesson, in the next one we’ll start building our room!

Introduction to Unity

Teaches the concepts of Unity required for world creation. Most everything here pertains exclusively to Unity development, and is not VRChat specific.

Introduction to Unity


In this lesson, we will build the geometry of our room!

There’s something quick we should get out of the way first: look at the bottom right corner of the screen to make sure auto generate lighting is off. If it's on, click it and in the new window at the bottom where it says auto-generate, uncheck the box, then close the window.

Before we start using Probuilder, there are some settings that should be configured first. Go to Edit>Preferences and then click Probuilder. There are some changes I’d like you to make here from the default settings, and for the sake of time and not having to explain things that many may not understand, I’ll just rapid fire them.

Enable Show Action Notifications
Enable Auto Resize Colliders
Change Static Editor Flags to Everything
Change Collider type to Box Collider

Now you can close the preferences window and open the Probuilder window by going to Tools>Probuilder>Probuilder Window. Progrids should already be in the top left corner, but if it’s not you can go to Tools>Progrids>Progrids Window. You can dock the Probuilder tab just like any other. You can also switch between the icon view if you prefer by right clicking the tab, and selecting Icon mode or Text mode.

Now that that’s done, let’s create our first Probuilder object! Click new shape, select cube, and confirm. You will now see that a cube appears in the scene! If you click the Probuilder icons in the scene view, you will see that on the cube appear vertices, edges, and faces: these are the fundamentals that make up the geometry of all 3D models. If you click on any of them you will be able to move them around in the scene view, and they will snap to the grid set by Progrids: you can increase or decrease the size of the grid by pressing + or _ on the keyboard, and reset the grid to 1 square meter by pressing 0.

We want to make a room, so let’s make a floor. Click new shape, select plane, change the axis to be up, and set the length to be 6 and the width to be 5 and then click build. Reset the transform so that it is at the origin.

Now, decrease the grid size so it is about 0.125m. Add a cube with the hotkey Ctrl+K. Then go into face mode (the hotkey is K), select a side face, and scale it down so that the mesh is 0.125m thick horizontally. Now drag it out so that the mesh is the same length as the floor. You can see the dimensions of your Probuilder object by looking at the Probuilder script component in the inspector. The average height of a room is about 2.4m-2.5m, so let’s make it 2.5m tall to snap easily with Progrids. Press ctrl+d to duplicate the wall and drag it over to the other side of the plane. Now press ctrl+k to add a cube and repeat the process to create walls for the remaining sides of the plane, and finally add a ceiling.

You’ve now created a box! But it doesn’t look very much like a room. The biggest thing it’s missing is a window! To make a window, select one of the walls, go into edge select mode and with one of the edges selected press alt+u to add an edge loop. This will add a new loop of edges bisecting your mesh perpendicular to the edge you selected. Your edge loop should be selected after you create it, so drag it out of the way and create 3 more to make a cutout for the window.

Now select the two faces where the window is going to be and press backspace to delete them (don’t press delete; it will delete the entire object!). Now select the edge ring where one of the faces used to be, hold shift and use the gizmo arrows to extrude new faces to bridge the two holes.

There’s a problem: the faces are not actually connected to each other. To fix this, go into vertex select mode and press ctrl+a to select all of the vertices of the mesh, and in the Probuilder tab, click weld vertices. This will merge vertices that occupy the same position in space, also known as overlapping vertices.

To add windows, we’re going to add a cube and just add loop cuts and extrude them inwards to make a window. Now you’re getting the hang of 3D modeling!

If you select vertex colors in the Probuilder tab, you can set faces to a vertex color, which can help with visualization and you can later set those vertex colors to actual materials.

We now have the basic geometry of our room. In the next lesson we will learn about bringing our surfaces to life with materials and textures.

Introduction to Unity

Textures and Materials

Now that we have our geometry, it’s time to apply some detail to the surfaces. The way this is done is through materials. Materials can be applied to the faces of geometry and combine a shader and one or multiple textures. To create a material, right click in the project tab and select Create>Material. The default shader is the standard shader, which is a physically based, or PBR shader.


Before we get too much into that, we should set up post processing in our scene. This can very easily be done with VRWorldToolkit. At the top menu bar, go to VRWorld Toolkit>Post Processing>Setup Post Processing and click OK. The defaults should be ideal but if you want to adjust them I would recommend first reading this guide by Silent.


I want you to go to this website, ambientCG, and pick a wood floor that you would like to see in your room. When you find one you like, check the dimensions (we’ll need these for later), MAKE SURE THE DIMENSIONS ARE THE SAME (not that non-square textures can’t be used, but they require more steps, are less optimized and don’t compress as well) download 1K PNG, extract, and import into Unity by creating a new folder labeled “_materials" in the project tab and dragging in the folder.


This is going to be the most theory intensive lesson because the knowledge of how PBR shaders work is necessary to make correct, good looking materials.


Having a single PBR shader ensures that all materials have consistent shading applied to them, just like in real life. PBR is based on real physical principles, so to understand PBR, you must understand how light interacts with surfaces in the real world. If we drag our material onto the floor we made in the last lesson, we can follow along to see how the standard shader incorporates these principles.


When light hits a surface, some of that light is reflected. Naturally, some light will be absorbed by the materials, but the reflected light is what allows them to be visible. The wavelengths that are absorbed, and, more importantly, the ones that are not, is what gives a surface its color. You can set a base color by clicking on the color picker of the albedo (also sometimes referred to as diffuse or base color).


In the color picker window, at the bottom you’ll see the red, green and blue channels. Above that you’ll see the color picker UI, where up and down controls value, left and right saturation, and the wheel around it controls hue. However, this setup is deceiving, because as you increase saturation, value is decreased. And even more confusing, the amount of value decrease varies depending on the hue, with yellow being the brightest hue and blue being the darkest. Here's a video that covers this in more detail but it is something to keep in mind.


The next parameter is specularity, which determines the way light is reflected off of a surface. A 100% specular surface would reflect all of the light rays that hit it at the same angle. At the opposite end of the spectrum is diffuse reflection, where light bounces around inside a material before being reflected in a random direction.


If you click the shader dropdown, you’ll see that there is a standard shader, and a standard (specular) shader. These are two different ways of thinking about PBR because metals are distinct from non-metals (aka dielectrics). Dielectrics typically don’t have a specular component, while metals typically don’t have a diffuse component (exceptions would be imperfections like rust or dirt). The specular workflow gives the artist more control but also allows for the creation of materials that aren’t physically possible. The metallic workflow is therefore generally easier and more intuitive; I would recommend using it over the Specular variant unless your material comes with a specular map.


Now for the other slider you see on the Standard shader: smoothness; this controls the clarity of the reflection. Many materials, like a lot of metals, can be quite reflective but that reflection can still be blurry. This is due to the many micro imperfections on the surface invisible to the naked eye but still affect the angle at which rays of light are reflected (In other programs this gloss or its inverse, roughness).


Another key component of PBR is fresnel, which is applied automatically; essentially, a surface is more reflective when viewed at more intense angles. Additionally, with transparent surfaces, like water on a lake, they are at their most transmissive when viewed perpendicular to the surface and at their most reflective when viewed parallel to the surface. You can easily see fresnel on spherical material previews.


Now let’s put the albedo map for our wood floor into the correct slot in our material! You should now see how the texture is tiled across the surface, but if we bring in a 2m tall capsule for player reference, the planks look too small. So to get the correct tiling scale we have to take the dimensions of the texture (in meters) from the website we got it from, whip out our calculator, and divide 1 by those dimensions. The result is what we plug into the X and Y tiling slots in the material, and now it’s the correct scale.


If you look around for textures, you will see diffuse and albedo, which are both supposed to go into the base color slot. The difference between these two similar texture types is that diffuse textures have directionless shading (like because of crevices where it’s harder for light to reach), while albedo textures have all their shading information removed and put into an ambient occlusion, or AO map. The advantage of this is that the material can react to changes in lighting, for example shining a flashlight against it.


Let’s plug in the AO map to our material! For it to display correctly, click on the texture in the project tab and in the inspector uncheck where it says sRGB (Color texture), since this is a grayscale texture. 


Most every surface exhibits details too small to reasonably recreate with geometry. This is where the normal map comes in. Place it into the appropriate slot, click the Fix Now button that appears and now you should see that the material now really “pops”. What a normal map does is change the angle at which light is reflected for each pixel in the texture, also called a texel. 


(Each pixel in the normal map represents a vector, where red is horizontal, green is vertical and blue is depth. The “default” blueish purple in a normal map is 50% red, 50% green, and 100% blue, which indicates no change in lighting angle of the corresponding surface.)


Heightmaps are used to fake depth in a material. This should also be set to non sRGB like the AO map. When we apply it we should see the change in our material but it may look a bit off. That’s because in Unity they are approximated by using a technique called parallax mapping, but it breaks when viewed at sharp angles. Typically I don’t set the intensity very high, either the default 0.02 or lower.


We talked a lot about reflection, and as you should see the reflection of the wood floor doesn’t look very accurate. It looks like it’s reflecting the sky! That’s because the reflection in objects is set to the skybox as the default. To change this, create a reflection probe by right clicking in the hierarchy and going to Lighting>Reflection Probe.


A reflection probe is essentially a 360 camera, capturing a spherical view of its surroundings. The resulting image is called a cubemap, and is used for the reflections in objects.


Place the reflection probe in the middle of the room. Under the reflection probe component in the inspector window, there should be two buttons, click on the left one first. This is the bounds, and the objects inside it will have their reflections affected by the probe. The right is the probe origin, or where the reflection probe will capture from. 


Now let’s make the material for our windows! Create a new material, name it glass, and drag it onto the window panes. Change the rendering mode to transparent, select the albedo color window and under the RGBA channels, decrease the A channel to 0. The A channel stands for alpha and it controls transparency. Now increase the smoothness to the maximum. Now we have a window that we can see through! Note that if you increase the metallic or specular the transparency decreases. Remember that increasing the specularity not only decreases the base color, it also decreases transparency.


The next important concept to understand is that of material slots. Each polygon is assigned a material, and material slots are a part of the mesh. You can see the assigned materials at the bottom of the inspector window when you click on the object.


We should always compress the textures in our world because they are going to be downloaded by every person who visits the world. To do this, click on the texture file in the inspector and check “crunch compression”. Your textures will now boast a much smaller file size, at the expense of compression artifacts (but no one is going to notice or care). Then click on the Android icon and check “override Android settings”. Then under format, click RGBA Compressed ASTC 6x6 block (this compression algorithm will ensure our textures do not look awful on Quest. Alternatively, you could switch to 4x4 block for better compression but with a higher file size). We should also probably reduce the max texture size on both platforms; this will also have the largest impact on the world’s download size. 


There are a couple of other settings we should change. Under Advanced, check Streaming Mip Maps (required for VRChat), change the filter to Trilinear and the Aniso level to 8. Now click the sliders icon in the top right to the inspector (in between the ? bubble and the 3 vertical dots) to create a preset. This way every texture you import from now on will take the settings from this preset (except for those imported from a UnityPackage). 


You can also go into VRWorldToolkit>Quick Functions>Mass Texture Importer to change all the textures in the Scene en masse. After a world build you can go into VRWorld Toolkit>World Debugger>Build Report to see all the assets in the world sorted by largest file size.


Unfortunately, Unity’s Standard shader doesn’t support plugging in roughness maps as is. These are very useful as they give varying smoothness throughout the material which adds realism (like a wet road with puddles, the puddles would be smooth while the road wouldn’t be). Unity only supports using smoothness maps (aka gloss maps, the inverse of a roughness map) as the alpha channel of the metallic or albedo texture. There are several ways to implement roughness maps: