This is a shader I created in three days for bottles in the game VR Bartender. The frame budget was very tight because there were many of these bottles in the scene, and it had to run at 70 fps on the Oculus Quest 1 (Android).

bottlefront.jpg

ginbottle.jpg Transparency is faked by using cubemaps.

The most common method of doing this (faking a liquid surface with two-sided rendering) was not an option here, because of the performance cost of using a mask or any form of transparency. My method is much more performant and works great on low-end devices.

bottleback.jpg

bottomliquid.jpg With my method, it’s possible to render the bottom part of the liquid surface and apply a different effect to it, such as brightening it up.

In my shader, the bottles appear transparent, but they are opaque. I used cubemaps for reflection and refraction.

calculations.jpg Calculating the water surface was the biggest challenge in the shader. At first, I tried to solve it analytically, but I failed. I decided to estimate it by combining the distance from the water plane (2) with Fresnel (3).

I estimate the surface of the liquid using a plane equation. I calculate the wobble on the CPU (the player can hold the bottles in their hand and move them) and pass it to the shader as a Vector3. The shader is completely branchless.

shaderCompexity.jpg The shader is efficient and runs smoothly on Android.