Time Spent: 3 weeks, and additional 3 weeks on and off for cubemap second iteration
Liquid Shader Goals/Scope:
- https://www.youtube.com/watch?v=p9NeBW4pgGk + https://twitter.com/Vuthric/status/1343678273776013312 // https://www.youtube.com/watch?v=2nB5v-fYjXw
- Liquid in bottles/containers that can grabbed, moved, rotated in VR (Start with a cylindrical container)
- Shaking the container should still create believable reaction
- Visual Meniscus
- Stretch: (for the future)
- Skirt Mesh
- Try something with Niagara and Grid2D
- Liquid can be poured out
References ( Research )
https://www.patreon.com/posts/quick-game-art-18245226
https://twitter.com/Un1cornHuntrSam/status/1475856497401679872
Vocabulary:
- Caustics
- Meniscus
water+ glass tube vs. mercury + glass tube - Tangent Space (Under the Context of Normals)
- Reflection
- Light bouncing off an object
- Refraction
- Light bouncing through an object
- Cube maps (Unreliable for reflection, but handy for refraction)
Normals
https://www.youtube.com/watch?v=hkTjreiookM “Normals are the direction of a face or vertex”
https://www.youtube.com/watch?v=LUjXAoP5GG0
https://www.youtube.com/watch?v=j2BEEtpPgdk
How do normals influence shadows?
Flat Shading: Face Normals
Faces have two sides each with their own normal
Smooth Shading: Vertex Normals
Meniscus
Tangent Space
Raytraced Sphere: https://www.youtube.com/watch?v=5ZHh8vUcEak
Ended up going with a 3 part simple visual solution that mimics how a meniscus looks.
The most confusing part of this was finding a way to keep the changes in the normals consistent on the material when an object is moved and rotated.
All 3 components are derived from the mask that influences the water level (feeds into the opacity mask)
straight to the opacity mask
influencing the normals
tangent space normal – unchecked
for a more 3d look
In a glass material
Keeping water volume at the right level (Fancy Math)
https://share.glasp.co/emerald/?p=w4ENzydZt4NBC7EFD96Y
Found this through a video – honestly, not sure if it works…
Angular Vel to Shear and Add Wobble
https://www.reddit.com/r/unrealengine/comments/q86t7i/are_quaternions_used_in_ue4/
https://forums.unrealengine.com/t/rotator-angles-independent/22890/2
https://forums.unrealengine.com/t/manually-calculate-and-apply-rotation-velocity/368255 ← Ended up going with this method of breaking the rotator and feeding the values back into a Vector.
I didn’t add in linear velocity…why is it necessary to do so? Is it only so that the liquid is more responsive to faster linear movement (movement not including rotation)? Is there some physics based reason?
➡️Added it in! Linear velocity will tilt the water according to the direction you are moving in so it’s pretty important and effective
More believable water behavior (believable when you shake the object)
I added a grab component, adjusted some values and popped this into VR!
Cubemap Reflections
The reflections from the out of the box UE simple glass material did not translate well into VR. The refractions and reflections were way off.
I used a material function from https://developer.arm.com/documentation/100959/0100/optimizations-and-optimization-techniques/cubemaps/implementing-reflections-in-unreal-engine for ray-box intersection to map the cubemap onto the material.
As well as this guide on reflection and refraction: https://www.youtube.com/watch?v=TNGNtVhCGvs
A great writeup on ray-box intersection: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection
Used the two-sided sign function to mask out certain areas and add them back together. The saturate node is key here.
Using inverted vertex normals to create the illusion of a frontface by making the backface be convex and adding that to the backface.
The localcorrection transparency looks amazing in editor, but doesn’t work well in VR due to inaccuracy. So I switched the transparency to a simple flipped camera input that is more accurate to the camera/head position in VR.
There was also the issue of the disappearing top on a non-spherical object…my goal is to use a cylinder so I accentuated the top with a mask that faded outward, multiplied by a texture sample. This ruins the illusion of reflections a bit…but it’s worth the trade.
Averaging out the vel over 5 frames to reduce jitter and error from VR controllers (ideally you would measure a predicted curve)
Adding the current velocity pos-lerp to resting velocity before the final output is super important for giving the wobble lag time. I kept getting stuck on this.
The order per frame goes: Set output for material with value > Lerp and reduce current vel avg > Add diff in vel from previous and current frame to reduced current vel avg > Populate vel history with value
This format allows us to base our lerp on higher vel values from past frames.
Physics is looking pretty nice now
Added some displacement with noise and a flowmap to mimic refraction for the water and glass.
Final result
Hoping to come back to this one day and polish more/try some other approaches
The final node graph (spaghetti!)