I’m working on a shader for a bottle containing liquid in Unreal Engine 5. I’m currently having trouble masking the bounds of the liquid’s surface based on the shape of the mesh (cross-section at the liquid level).
For now, my mesh is opaque and in default lit mode, and I’m faking the reflection/transparency of the liquid. To create the liquid surface, I drew a horizontal infinite plane at the liquid level (following left image).
What I’d like to do is crop this plane according to the mesh’s bounds, as shown here (random-looking bottle cross-section).
I need a way to get a mask containing the cross-section of the container mesh (square bottle, cylindrical bottle) at the liquid level (like the green flat part in the right image, but as a mask).
But the problem is that I can’t use depthFade (I’d like to have everything inside one material, so no slicing with a plane and using a depthFade). I’ve also tried to use a render target, but I don’t believe it’s the best solution because I would have trouble rendering multiple bottles at the same time, and I have more than just the cross-section.
I’ve also thought about using signed distance fields to mask my plane. This would involve converting it to world coordinates and culling based on the value of the signed distance field of the mesh bounds (I believe that if the distance field < 0 then it is inside ?), but I’m having trouble figuring that out.
I’m fairly new to shaders, so any advice would be nice .
Using Blueprints:
You could also use 2 line traces to get the elipse radius of the pour direction and the orthogonal radius, and scale the (round) surface plane depending on that. Helpful for an open container if you want to determine if fluid is spilled or not. Needs additional material logic to make it look okay.
I don’t know if this helps. I made a simple water bottle shader a few months ago for fun, and this material function is the main method for the shader. After getting the mask I made this shader with a masked unlit material double-sided.
The topic link (3rd point) was the way to go, thanks !
I ended up using a signed distance field and clamping my plane according to the distance field’s value, which allowed me to render only the cross section.
However, if anyone comes across this in the future, I think it’s worth mentioning that mesh distance fields have been disabled on Intel graphics cards.
“All Mesh Distance Field features have been disabled on Intel cards because the HD 4000 hangs in the RHICreateTexture3D call to allocate the large atlas.”
I provided you with the files, there are two simple materials, one texture, and one blueprint actor. Just hook up the texture in the material, and the materials to the actor and you should see this result.
The project is made in Unreal 5.1.
Thinker a little bit with the materials and you will see they are extremely easy to grasp.
Ivan, this is great stuff, you made my life much easier! Is it possible to get the file you uploaded on Drive? The link is no longer working. Thanks for your help.
The assets are made in Unreal 5.1, just put them in the content folder.
If it doesn’t automatically connect the reference, it is easy to set up, there is only one blueprint and two mesh with the provided two materials.