As my new ray tracer is spectral I am rewriting some of the basics from scratch including dielectric code. I figured I could cut and paste some stuff out of ancient "
ray tracing news" but ran into some problems with normal vectors. So I am re-deriving this for my own benefit.
|
Sketch created with limnu iphone app from limnu.com |
All renderers have some convention about which way surface normals point and whether that depends on incoming rays. I am a fan of surfaces being boundaries between materials, and a dielectric has a surface normal
N pointing to the side with refractive index
n. One thing that means is that in the diagram
N might be pointing "down" along the dotted line.
First what about reflection? It is usually the classic formula:
S =
D - 2*
N*dot(
D,
N)
Does that formula still work if
N points along the dotted line? Happily, yes-- try substituting -
N in there and you get a "-" on the
N and the dot product and they cancel. Also,
D need not be a unit vector. I rarely require that in my ray tracers so I can use instancing if I want.
N however does need to be a unit vector.
Now what about refraction? It obeys Snell's law:
n sin(
theta) =
n' sin(
theta')
We can use the same trick as in reflection where we use
N and
D as a 2D basis. First let's make life easy on ourselves and assume
D is a unit vector and
N points "up" like in the picture, and make an orthogonal basis (let's change the sin() and cos() with c, c', s, s')
D = -c
N + s
Q
Here
Q is to the right and perpendicular to
N. We don't know what is is yet, but it we know what it is by rearranging the terms above to be get
Q = (
D + c
N) / s
We also know that
T = -c'
N + s'*
Q
We know c = -dot(
D,
N), and s = sqrt(1 - c^2)
Further we know that s' = (
n/
n') s
Right there is a place we can get into trouble-- n can be high (over 2 for diamond) so if the more dense medium is where
D is (the top medium), we could have s > 1. In that case we get all reflection and no refraction (total internal reflection). Here's a nice image of that:
|
The water acts as a perfect mirror due to total internal reflection (from wikipedia) |
OK plug and chug the algebra:
T = -c'
N + s'
Q
T = -c'
N + s'(
D + c
N) / s
We know s'/s = n'/n.
We also know c' = sqrt(1-s'^2) = sqrt(1 - (n/n')^2 (1-c^2) ).
T = (n'/n)
D +(c(n'/n)
- sqrt(1 - (n/n')^2 (1-c^2) ))
N
putting back in c = -dot(
D, N) we get
T = (n'/n) D +(-dot(D, N)(n'/n) - sqrt(1 - (n/n')^2 (1-dot(D, N)^2) )) N
Ok! That agrees with the ray tracing news formula. Now what happens when
N points down? Only the last term is different:
T = (n'/n)
D +(-dot(
D, N)(n'/n) + sqrt(1 - (n/n')^2 (1-dot(
D, N)^2) ))
N
Well isn't that annoying? That sign difference is just sgn(dot(
D, N)). I never know how to best code that sort of thing, but when in doubt, be very readable!
if (dot(D,N) > 0) temp_normal = -N // now proceed with original formula