Barista VR Dev Update #2
The last update to this project was a while ago, but you can see where it was officially left off here.
You can see the code for the project on GitHub
As promised in my last post, I’ve spent a fair bit of time in the last few weeks reviving BaristaVR. After refactoring some code and restructuring some components, I’ve gotten it to a point where all the original functionality is working again, alongside some new features and other improvements. Let’s see where we’re at.
Jump to a section
What’s New
Most of the prospective features promised at the end of the last update have been implemented, and in addition to the technically repeatable game loop from last time, there’s a bit more of an actual game to play now.
Ingredients
I’ve completed an initial implementation of the ingredient system. Each container capable of being filled with liquid stores a number of attributes related to what sort of drink it is, including:
- Ingredients, and how much of each the vessel contains
- Volume
- Temperature
- Color
When you break it down like this, it’s reasonably straightforward to compare a real (virtual) drink to an idealized beverage. We can call a latte 12% espresso, 85% steamed milk, and 3% syrup, and get a meaningful “score” when comparing those ratios to a drink made by the player. Similarly, we can specify an ideal temperature for a drink, and an expected fill percentage. If a drink sits for too long and cools down, or the player spills half of it on the way to the customer, the score can be lowered accordingly.
Milk Steaming
Another core component of a barista game, putting the steam wand in a filled milk pitcher and turning it on will now steam the milk, increasing the temperature and converting it from plain old milk to steamed milk. The temperature is visible on the display on the espresso machine, to give the player an idea of how long to steam the milk for.
Creating a Semi-Playable Game
With most of the core functionality roughly in place, I thought it would be good to have some simple “game” to showcase and test the ingredients system. I’ve added an area where the player is prompted to create a randomly generated drink. When they finish and place it on the counter, they’ll be scored on how “good” the drink is. This is based on the following formula:
Here, S is the overall score, ri and Ri are the ratios of the ith expected ingredient, uj is the amount of the jth unknown ingredient, L and l are the liquid fill volumes, and T and t are the liquid temperatures. Capital variables represent attributes of the reference beverage, and lowercase represent those of the created drink.
It could probably use some work, though it works reasonably well for now. For the future, I’ll likely weight the amount of unknown ingredients by total volume, and add a max(0, ...)
for the fill volumes so the player isn’t punished for missing a few milliliters. It would also make things easier if the expected ratios were given a threshold so the player doesn’t have to match them exactly.
In short, the player is awarded points for each ingredient that matches the expected ratio of the reference beverage. They are punished for unexpected ingredients, there being too much or too little liquid, and the drink being too hot or too cold.
Revisiting Fluids
Simulating fluids is a crucial component of this game, since being a barista is really just pouring different liquids between containers. As such, I want the liquids to look and feel nice. In the previous update, linked above, you can see that there’s a decent foundation laid down, but there’s a lot of room for improvement. I’ve recently been playing around with different approaches to get something that performs well and behaves as one would expect.
Creating realistic liquids in the game can be broken down roughly into two problems: visualizing a container filled with liquid, and simulating pouring liquid out of a container (and potentially into another container). The first problem is conceptually pretty easy (especially with better shader knowledge than I have), but the second is quite a bit more complicated.
Liquid Containers
Since pretty much the inception of the project, I’ve been using Kronnect’s Liquid Volume asset to simulate a container filled with liquid. It’s a great asset, with an active and devoted developer, but I ran into a few issues with the VR rendering, and have moved away from it for the time being. Admittedly any weirdness could be because of my shoddy ProBuilder models, so I plan to revisit it in the future.
In the interim, I’m using the open source Unity Simple Liquid, which conveniently had a pretty well implemented pouring system integrated. It works well for the time being, with none of the rendering issues I’d run into before. Overall it behaves similarly to Liquid Volume for my needs, though it certainly isn’t as feature heavy (Liquid Volume has options for smoke, foam, and all sorts of other configuration for the liquid itself).
Simulating Pouring
This article on UploadVR, Why a Cup of Coffee in ‘Job Simulator’ Took 850 Hours to Make, shines some light on how difficult it can be to get liquid pouring right (even with all the now dead Youtube links). While I fortunately stand on the shoulders of some giants who paved the road for general VR interaction (grabbing, throwing, twisting, etc.), optimized and realistic flowing liquid is still pretty tricky to achieve.
Previously, poured liquids in the game have been simulated with many tiny spheres, each representing a drop. This actually turned out to be a decent approach. It’s easy to detect collisions between liquid vessels and the poured liquid, and as you increase the number of particles and decrease their size, their behavior becomes more and more liquid-like (if we get small enough we can almost perfectly simulate liquid!). Unfortunately and unsurprisingly, it isn’t very performant. Dumping just two cups out at once tanks the frame rate, and that’s with a 2060 Super in a simple scene. Not very scalable.
I started exploring using a particle system a while back, which conveniently is the also how Unity Simple Liquid approaches solving the issue. This is much more performant, and Unity’s particle system has quite a few features that help make the liquid look nicer. Trails mask spherical particles with a more liquidy stream, and sub-emitters can be used to simulate puddles and splashes of liquid. Truthfully I have quite a lot of tweaking to do on this front, but it’s a good start.
One issue with using a particle system is that it’s more difficult to detect collisions between the poured liquid and containers that can catch the liquid. Whereas with the sphere-based implementation, each drop can send an event when it collides with a container, the particle system doesn’t have this granularity. Unity Simple Liquid uses a raycast sent downward from the lowest point of the rim of the pouring liquid to find potential colliding containers. It’s actually an interestingly complex solution, as if it hits a non-liquid collider, it will find the slant of the surface and send a raycast at that angle to find the next container, five times, essentially simulating the liquid trickling down a series of slopes. This is clever and surprisingly thorough, but there are a couple issues, both of which are maybe easily fixable.
First, the receiving container starts filling well before any of the pouring liquid even reaches it. With a big enough height difference, you could fill an entire cup before a drop of liquid even falls into it. I think this could be pretty easily solved by getting the vertical distance to the container hit by the raycast and calculating the time it would take the liquid to fall. Second, realistic liquid doesn’t just fall straight down from the pouring point. This sometimes leads to either liquid falling in the container but not filling it, or liquid missing the container but still filling it. I could probably offset the origin of the raycast dependent on the pour angle to make the effect more accurate.
Approaching Alpha
While there’s clearly still some improvements to be made to the fundamentals, I don’t expect to get them perfect at this point. I want to achieve a minimum playable game before I deep dive into fine tuning the trickier systems. I’ve been working on the game for quite a while now (albeit slowly), and I think it would be beneficial to have a more concrete “starting point” that I can get feedback on and iterate from. As I intended to do nearly a year and a half ago, I’m going to work on polishing things up a bit and put out an initial alpha build.
There are a few things I’d like to do before I call it ready:
- Tinker with the drink scoring system to make it more reliable and less punishing
- Make the pouring system more realistic, and fix funkiness with the particle emitter
- Color mixing needs some love as well
- Add a brief tutorial to explain the basics of the game
- Find some better hand models, preferably ones that aren’t leather gloves
Once these improvements are made, along with some minor cleanup and visual improvements, I look forward to releasing a rough, but playable, version of the game. I’ll probably release it publicly on the Github repo, and will post about it here when I’ve done so.
Also there’s a decent code cleanup imminent, but I don’t want to get in the weeds with that and delay the alpha for god knows how much longer.