4
\$\begingroup\$

I'd like to mimic this effect seen in Half Life: Alyx:

enter image description here

I can't figure out what is going on here, people say "it is just a shader effect it isn't simulating anything", but I don't think that is true at all, it appears to be doing some sort of surface only fluid dynamics, but I'd have no idea what technique is actually used underneath.

My best guess is that

  • each object has a "origin" plane associated with each bottle that "exists" outside of the bottle and always fixed to some origin relative to the bottle

  • then waves ala gerstener waves are generated via movement somehow

  • the surface is raymarched only within bottle geometry

  • when below the surface additional ray marching is done for bubbles which are generated via potentially 4D noise, or a set number of bubbles are generated then rendered as round sprites or independently of noise

  • foam is generated based on a uniform value that is passed in that determines the "shakey" ness of the bottle, which makes values closer to the fluid surface more opaque and white.

  • fluid volumetric opacity doesn't necessarily have to be raymarched, but would likely be with the rest of this stuff being raymarched. Using beers law to attenuate light based on distance and density through fluid.

But I'm really not understanding how the plausibly physically correct surface deformation is happening. How would I do something similar? I've seen some other posts that just have the surface wobble, but if you look in the video, it is more than just surface wobble, there is actual surface deformation.

\$\endgroup\$
13
\$\begingroup\$

I've been redirected here after posting this on twitter : https://twitter.com/Gaxil/status/1268165270541078529

I can give you some details of my implementation, even if I know that it's a quite different approach of the original one.

So, in the vertex shader, I access a compute buffer in read/write mode. That allows me to store the world position of the vertex from the previous frame and so to extract the local velocity afterward.

Concerning the physics, it's springs based and everything is stored in the compute buffer as well ... I have an offset and a speed, it's only a couple of float as it is on one axis only (perpendicular to liquid surface). Every frame I:

  • Dampen the current velocity to avoid ever moving spring.
  • I compute an acceleration depending on the local velocity dot the vertex position, modulated by a sine depending on the world pos (see explanation above).
  • That acceleration is added to the velocity
  • The velocity is added to the position.
  • I also add to that velocity an acceleration that depends on the current offset, to bring it to a rest position, the further away from the rest position the stronger the acceleration.
  • I add the velocity to the offset

And so, that offset is added to the plane position, horizontal, above the center of the object. Also, I had to cheat a bit to avoid having geometry projected outside of the volume ...

For the foam and bubbles, I store an 'activity' level also in the compute buffer and this is decreased every frames with a constant but it's also increased by the abs(velocity) of the spring. The foam is added to the y position to do an extra displacement ... and it is also used as mask to colorize the foam part and to display some 3D noise for the bubbles.

And that's roughly all I've done here ...

The glass is a separate shader rendered twice (back and front). It's certainly a bit overkill and I've gone also a bit wild on the geometry, but I wanted to push that as far as I can to have something quite realistic. This can certainly be simplified and optimized for real usages.

I hope this helps, cheers!

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.