With this post I’m gonna try to explain some difficulties and processes that came up when I was trying to convert my previous WRXR VR experience into a web capable program. Our contact from the Department of Astrology wanted a web build of the experience to be made for this years Astrofest which is taking place online due to the current climate. In an attempt to let as many people access the program, the VR aspect had to be removed and replaced with controls capable with just mouse and keyboard.
So, first and foremost, I removed all the VRTK scripts and assets from the program. This actually didn’t break down the system as much as I had feared it would thanks to my previous “index button” script’s structure. The Index Button didn’t actually reference VRTK directly at all, merely looking for a specific collider (i.e. the one on the index of the VRTK finger) to collide with it and which direction that collision came from before running press and activation scripts. As such, I was able to very simply add in extra checks to accommodate mouse clicking. I initially used Unity Monobehavior’s built in “OnMouse” functions, but due to an issue I’ll explain later in this post, that had to be changed to a system where mouse clicks cast a ray from the camera. Either way, over half the interactions of the program functioned just fine without the VRTK assets, they just needed a new activation source.
The rest of the interaction, however, didn’t. My grabbing system was heavily reliant on VR’s hands for grabbing and moving pieces freely and the player’s head motions allowed camera movement. These of course were removed in the conversion so replacements had to be found and developed. First, for the general camera control, there’s really no need to build your own first-person controller at this point as it’s a solved system with MANY plugins available. It was simple enough to find a well made First-Person controller and put it in the scene to replace the VR avatar. I did have to tweak some settings in it to lock the controller in place when in silo mode as the platform still moved in it’s set motion (using arrow keys ans W/S to replace the three control stick axes I was using before) but overall it was a simple replacement. The grabbing was more complex.
With no hands, the primary tool of being able to explore the important rocket pieces up close needed an alternative. I settled on a click grab system where clicking the object would move it to be the child of an empty object set in front of the camera. With the first-person controller, this let the player easily move the piece around to start. Then I added controls to manipulate the camera’s hold object (pushing and pulling it from the camera and rotating it). This lets the player manipulate the position and rotation of the object relative to the camera while it’s held. Since you can no longer grab the individual shell pieces of the main parts to see the insides, I also added the ability to right click to hide those shells entirely. Clicking again releases the object.
Once I got the overall mechanics figured out, I tried building into WebGL and stumbled upon a whole slew of new issues. The big one right from the start was that I literally couldn’t build into WebGL so long as my scripts even referenced VR scripts as Unity’s building system strings along any script referenced by a script in the scene, even if that script isn’t used. So my scene management scripts that all mentioned VRTK scripts had to be adjusted. However, I didn’t want to ruin the VR version of the program either. So I had to make “web” versions of those managers and apply them to the proper objects. This wasn’t so bad as there’s only one of each manager in the scene. This made me realize how much of a bullet I dodged by having my buttons not reference VRTK as replacing all the button scripts would have been awful. With that done I was able to fully remove VR from the build list and get a web build going.
This led to the second major problem: the way WebGL works with cursor locking. See, in most first-person applications, when you click on the window your mouse is hidden and locked in place so that your movements with the mouse still register but the cursor doesn’t move out of the window if you need to click on stuff in the application. This is possible with WebGL and the first-person controller I found actually had built in cursor locking. The issue is that while WebGL does allow locking, it can’t drag your cursor to the middle of the screen like this first-person controller was doing before. As such, all my scripts trying to use OnMouse got messed up as if the cursor was say, in the upper right of the application when locked, then you could only click on buttons and pieces if you moved them to the upper right of the screen first. This is why I ended up switching all my scripts involving clicking from OnMouse to just looking for when the mouse button was clicked and casting a ray from the camera center to act in a similar fashion no matter where the cursor was.
The third issue with WebGL was the way cursor lock works in the first place. It took me a while to figure it out, but essentially you have to account for two cursor lock systems: the web browser’s and the applications. When your application is set to cursor lock, that doesn’t actually lock the cursor immediately. Rather the next time the mouse clicks on the program directly it sends a message to the browser to lock the cursor. So to lock the cursor if it was unlocked before (say, if you want to let them pause the experience and get their cursor back) you have to do a two step process where something in game sets to cursor lock, then the user clicks the application again. To this end, I put in a pause menu that asks the player to click the button in the center of the screen to resume. This click actually doesn’t lock the cursor immediately but rather sets the cursor lock in place so the next time they click (say to click a button or a piece) it locks the cursor properly. The reverse of this occurs when unlocking however. The only way to tell the web browser to unlock the cursor is by pressing the Escape key. This overrides all other escape key functions within the application, so given my pause menu is brought up by hitting escape you’d actually have to press it twice to properly pause the game. Once to stop the cursor lock which supersedes all other Escape inputs, then again to actually pause the game. I need to test more on how these cursor lock systems work to find the best setup for allowing the user to easily enter and exit the game window with proper locking, but for the time being this system works well enough.
The overall conversion took me longer than I expected it would. From figuring out control replacements to properly detaching the VR scripts to figuring out what WebGL does and doesn’t allow, the process is more complicated than just swapping some controls. There was also certainly a clear loss in exploratory options with the change in how the objects are grabbed and the sense of scale is lost in the experience itself. That said, overall the conversion wasn’t too bad in this case due to the way things were structured and how the experience focused on physical exploration rather than more complex physical activity. The result is a web version of the WRXR experience that gets the point across well enough, though the VR experience is still noticeably better in all regards.
Leave a Reply