Ryan Brucks is always an inspiration, even if at least half of what he says is way over my head. But with a bit of time, things come together. His posts on twitter (here is an overview), give insight on creating "fake" fluid sims in a bottle, much like Half Life Alyx's bottles. To get to where he was, I had to break down a few problems.
First some prerequisites. There are some basic settings you must have enabled to make any of this work:
- raytracing enabled (see documentation) - PostProcessVolume in your scene with Translucency set to raytraced and refractions ON
- Translucent material should be set to 2-sided, translucent, with the LightingMode set to SurfaceTranslucencyVolume and toggle RenderAfterDOF to OFF
Initially, I had to figure out how UE4 handles IOR within the context of raytracing. It uses the Disney BRDF which connects specular and IOR, so the specular input controls the IndexOfRefraction for your translucent material. Be aware that when raytracing refractions, the older-school refraction material input does nothing. Here's a screenshot of my material base for simple Glass:
So the Material Function in there does a conversion using a formula: Specular = sqr((IOR-1)/(IOR+1))/0.08 With thanks to Mike Zheng. Here's a look inside the MaterialFunction:
This has a switch that chooses between normal SpecularAmount when not raytracing, and the formula conversion for when you are raytracing. This allows you to input what you normally expect as water or glass IOR values like 1.5 for glass and 1.3 for water. If you're wondering what that line down from the Normal input was for, that's just some extra condensation controls. You can probably just ignore it, but here it is just to be complete.
So with this, we have a base for glass. Now, extend the same to fluid.
The ability to control RotationAngle and FillLevel are nice to have features which Ryan goes over in general, but is implemented here, with credit from reference from a Marketplace Asset by 3DVFX
Here's a breakdown of the simple Coke liquid material seen in the video above. The parts responsible for the FillLevel, rotation and upcoming dynamics have been placed into another MaterialFunction circled in red. To be clear, the way these materials are assigned is on a bottle mesh that has the outer faces set to the MI_Glass material, and the inner faces set to MI_CokeDynamic based on the material below. An important note in the liquid material are the 2 IOR settings. For the glass, it lerped between the IOR of glass and air (1.5 and 1). In this case, we are lerping between liquid and glass (1.33 and 1.5). CheapContrast was added just to be able to sharpen the edge in cases where the asset was smaller.
And here is the MF_LiquidDynamics. This takes care of orienting the angle of the liquid to stay horizontal however you rotate the bottle, as well as providing an input for FillHeight.
This brings us to the end of this round. We've hopefully gotten our heads around raytracing refractions in Unreal. I haven't mentioned some of the more basic bits, like making sure you have a PostProcess in your scene and you enable raytraced translucency and enable refractions, otherwise none of this works;)
Next, I'll soon hopefully go over some more advanced dynamics and a trick for getting cinematic DepthOfField to work with translucent objects.