Lately, our twitter feed, was literally full
of bottles containing liquid directly from the last chapter of Half-Life (Alyx). A lot of good talented creators made their
version of this cool effect. Today we'll create our version of it on Unity. The effect consists in showing a mesh, inside
the bottle, and make it look like a liquid. To easily care about the lighting, we used a surface shader instead of a fragment. Besides a good aesthetic, to make a mesh looking
like a liquid we have to cut the surface at a certain level. So we started from that point. In our liquid shader, we exposed a position
and a normal vector that represent a plane. That plane is the max level of the liquid. Using the dot product between the mesh position
minus the plane position, and the normal of the plane, we were able
to determine which part of the mesh we need to show. We cut out the other part discarding the color
if the dot product is higher than zero. Because we sliced out the mesh we had divided the front and the back faces. For the front faces, everything was quite
simple. We used color, a texture, a normal map, the
glossiness, and the metallic value. For the back faces, besides the color, the
metallic, and the glossiness, we needed to transform the normal vector to match the normal
of the plane used before. We needed it to pretend that the upper border
of the mesh was closed and cover the hole. To do that, since we used a surface shader,
we had to create a matrix that converts the world coordinates to the tangent space. Also, we used a normal map with the world
UV to enhance the refraction while moving. Using a script, we connected the position
and the normal of the plane in the shader with a real quad. To pretend to keep the liquid volume inside
the bottle, we adjust the position of the quad depending on the bottle rotation. We exposed a property called "bottleHeight". We consider the top of the bottle starting
from the base and going up at the bottle "bottleHeight" distance. We moved the quad on this line, and we did
a proportion to figure out the distance that it has to keep from the base. If the top of the bottle has a lower Y value
of the base, we switch them. To approximate the level of the liquid in
a non-regular shape we simply used a lower value for the "bottleHeight" property. Let's talk about the movement, while the player moves the bottle we calculate the velocity and keep track of that. We rotate the quad to facing that direction
so the liquid seems to be affected by physics. When the magnitude of the velocity is zero,
so nobody is moving the bottle, we use the accumulated velocity to simulate the inertia. With the ping-pong function, we go back and
forth from the facing direction to the opposite one. Carrying that value to zero in time, allows
us to simulate the end of the inertia. We did the same operations even for the angular
velocity while the player rotates the bottle. Back in the shader, we interacted with the
stencil buffer to cover the backfaces and improve the top surface aesthetic using also
a custom shader on the quad. The stencil buffer, allows us to prepare a
mask of bit and render an object only if the buffer has the same values. So we need a shader that writes on the stencil
buffer and another one that can read from that. In the liquid shader, we divide the two cases
to avoid covering also the front faces. If you want to go deeper in the stencil buffer
check the description below and you will find Harry's and Ronja's articles about that. In both of the shaders, we provide a property
that represents if the inertia is still present. We used that property in the liquid to animate
our threshold in the "checkVisibility" function and ruffle the top edges. In the top surface shader, instead, we used
that property to enhance the normal map value and faking a ripple. As an additional and optional experiment,
we wanted to allow the liquid material to be transparent. In this case, we drew both faces: back and
front, so we decided to use a grab pass. A grab pass is a particular pass that grabs
the content of the scene and draws it into a texture. This is can be expansive in terms
of resources but it's commonly used when you want to distort an image. We used that in a previous video where we
recreated the heat distortion. After sampling the texture, we used the alpha
property of the color as a weight for the lerp between the color or the background texture. We downloaded a model of a bottle from Sketchfab
and merge the inner meshes to use a single material. This is the final result! If you follow us, you know that in the last
weeks, we are working on a framework to create web augmented reality experiences from Unity. So, as the last test, we wanted to try this
in our "work in progress" framework. Don't forget to subscribe, smash the like
button and follow us on the other socials. Also, If you are interested you are welcome to our
discord server. See you next time. Cheers