(and why you’ve been doing it wrong your whole life)
It’s hard to imagine a world without wine-glass tutorials, there are hundreds of them! Heck, I made two myself a few years ago.
But there’s a problem! We’ve been teaching (and learning) the wrong method this whole time! I know it’s a bad idea to teach complicated physics stuff in a noob tutorial, but teaching the wrong thing sounds a bit worse.
So good morning class! Today we’re going to learn about interfaces! (not that kind of interface). Open your text books to page 269 and lets find out why we’re all idiots!
This is probably the method you know – a normal model of a glass with some liquid fitting snugly inside it.
The reason why this is wrong is because it leaves a small air gap between the fluid and the glass, and the bevel of the liquid at the top is the wrong way around.
An interface is a surface forming a common boundary among two different phases of matter, such as an insoluble solid and a liquid, two immiscible liquids, a liquid and an insoluble gas or a liquid and vacuum. [wikipedia]
The index of refraction (IOR) of water as we know it is 1.33. That of glass is about 1.5 (depending on the type). Great. so punch in those values and you should get a realistic result right? Wrong.
The IOR we put in the Glass shader is not the IOR of the medium (glass or fluid) itself, but really the IOR of that interface – the boundary between the two mediums (glass and air, or liquid and air). The calculation for this is mystical interface IOR is quite simple. Air has an IOR of 1.0, since by definition refractive indices are relative to air, and the IOR of the interface is calculated by dividing the IOR of the medium being refracted (the glass) by the incident medium (the air).
So in the case of the air-glass interface, the IOR stays at 1.5 (1.5/1 = 1.5). However where the fluid and the glass touch, there is no air there, thus the interface is between glass and fluid. Assuming the fluid is water, the interface IOR would be 0.8 (1.33/1.5).
But here’s another problem: An IOR below 1.0 implies that light travels through this medium faster than it does through a vacuum. Although this would be a great way to imagine multi-coloured refractive FTL engines, it’s not possible*. However! in this case it simply means we need to invert this value (1/0.8 = 1.25), and to do so and remain physically accurate, invert the normals of the interface too.
So now you’re probably wondering which surface we should invert – the glass or the fluid? The answer: Neither. And both!
We need to stop thinking about this in terms of physical objects, the air the water and the glass, but rather as the interfaces between them. Instead of two materials, we need three: the glass, the surface of the water, and the glass-water interface.
You can join these three objects together, that’s not an issue, and even merge the connecting vertices of the glass and the interface. However you cannot merge the verts of the surface and the interface, and here’s why:
We need to invert the normals of the glass-water interface in order to get the IOR above 1, such that the normals are consistent with the normals of the glass, but inconsistent with the surface of the liquid. Merging the verts of that and the glass would cause shading artifacts since at the join the face normals would be opposite each other. But merging the glass and the surface is perfectly fine as their normals would be consistent.
Lastly, don’t forget about surface tension, so make the curve of the liquid’s surface concave:
It’s a bit of a strange thing to understand, so feel free to download and tear apart the blend.
Alternately, there is another method that seems to give similar results and is much simpler, however it does not allow you to use the Ray Length output for absorption:
This image is from a VRay tutorial – the idea is to simply scale the liquid up so that there is a small area where the liquid and glass overlap, rather than leaving a gap between them. But since there is now a tiny bit of volume there, the Ray Length output will give us this overlapping volume instead of the whole fluid, so absorption doesn’t work. But if you don’t care about absorption, then by all means use this method instead. This duplicate geometry probably won’t have any noticeable impact on memory or speed.
And now for a little disclaimer: All of this is fairly new to me, so if you find that something I’ve said is incorrect, please correct me for the benefit of future readers and for myself. I could of course have told you about the last method first, but I think it’s good to understand the whole interface thing and not blindly using physical values such as IOR without knowledge of how they’re supposed to work.
Interesting read. Just two small technical comments: the IOR of air is actually slightly higher than 1.0 as the reference is vacuum and not air (http://hyperphysics.phy-astr.gsu.edu/hbase/tables/indrf.html).
Another more technical thing for those interested in physics:
The scale, l, of the capillary effect on the edge can be quite easily estimated. It is clear that the relevant measures must be the surface tension, Y (should be a gamma), density, p (should be rho), and gravity g. From dimensional analysis we see that these must be combined as l = sqrt(Y/(g*p)). Now, Y can be looked up and is 0.075 J m^(-2). g is around 10 N/kg and p is 1000 kg m^(-3). Putting it all in yields l = 2.7 mm which is then the size the small curvy part of the liquid surface should have.
Indeed, though I don’t think 1.000293 will look much different from 1.0.
I’m glad there’s a formula for that little curve – is Y some constant based on viscosity?
No, it actually has nothing to do with viscosity. Y is the surface tension and is actually a much simpler thing than viscosity that can vary with the velocity of the fluid in strange ways (see for example http://www.youtube.com/watch?v=amfjWWMg9c0 or try to mix cornstarch and water yourself to make a non-newtonic fluid). The surface tension is the cost of having a surface – imagine how the molecules at the surface “misses” a molecule to bind to as there is nothing above them. A rough estimate for water would be:
The bond strength inside a molecule is in the order of eV so we take one tenth of that as it is between molecules. The distance between atoms in a solid or a liquid is approx 0.3 nm. Energy per area: Y = 0.1 eV/(0.3 nm)^2 = 0.178 J/m^2 approx twice at much as the actual value.
Interesting – do you have a link to a table of these surface tension values?
Here you go:
The table is at the bottom.
Nice, thanks. I never knew water/interfaces could be quite so interesing :)
I actually learned this a while back when watching a tutorial for LuxRender. But I haven’t used that method in a while so thanks for refreshing me on that haha. Great post
The question is: what one have to do with animation? =) VRay technique working well but if we need absorbance too?
this is excellent. I dont know if i commented on how awesome this and all your blog entries are but keep it up man. This is a must read page for any blender artist.
Thanks sir :)
Nice! I think that the absorbtion may not be a problem if a volume shader is used. It seems to work fine for me, even with an overlap. And now that Volumes can be rendered in Cycles on GPU in the newest Blender release, it might be best to use volume shaders anyways. Anyways, i’ve learned something about IoR’s.
One thing I can add is that the IOR of water can be put 0.8. No need to flip the normals. Although the speed of light can not exceed c, but rendering engines do not include in any way the speed of light. The only thing that counts is the angles, and these are determine by IOR. In other words, the definition of the refractive index as the ratio of light velocity in medium and the velocity of light in vacuum here loses its sens.
Indeed you’re right! It never used to work like that, but Brecht fixed it after publishing this months ago :)
So wait…what on earth to do if running a fluid simulation! Is there a way to address this! Perhaps they should have been mentioned together…
Wait. I’m not too clear on this front. So does blender just divide the values of the incident medium’s IOR by the refractive medium’s IOR? Because that will result in the 0.8 value you mentioned.
Interesting piece, how would you tackle the issue of glass that is within a liquid that is behind glass, ie: a glass dropper inside a bottle which is full of liquid.?
Can the surface of the glass be deleted altogether, and replaced with the interface surface?
Can you simply assign a interface material to the region of the glass where the liquid, um interfaces?
This was absolutely what I was looking for! Thank you so much for this article.
Thank you Greg. Another advantage of your technique you didn’t seem to mention is that it avoids having a double reflection on the glass in the part where there is liquid, which is also accurate. So, awesome technique !
Wait, did I have no eyes ? I can totally see double reflections now. But not on everything. I don’t know what’s going on.