Modeling light as rays is widely used in computer graphics and lens design. I encountered this problem when I tried to do some optical design but had no access to commercial ray-tracing software, such as ZEMAX OpticStudio or LightTools. During my attempt of implementing a ray-tracing program for my own research, I did not find a single article or book chapter that serves a one-stop manual that details the ray-tracing from theory to implementation. I therefore parepared this tutorial to fill this gap.
This article demonstrates a simple two-dimensional ray-tracing algorithms, with a focus on concnetrator lens design. For lens design with spherical lens surfaces, using ray transfer matrix would be easier to implement and computationally efficient.
Live demonstrating code
I wrote a vanilla python ray-tracing implmentation with explaination in a Jupyter Notebook run by Kaggle Kernel.
Outline of ray-tracing algorithm
In a ray tracing simulation, light is thought of as a bunch of light rays. You can also think the light are a bunch of particles (i.e. photons), and the “rays” are the trajectory of movements of these particles. When a light ray encouters a surface, some of its energy is refelcted, some is refracted and some are absorbed, and each of the splitted rays keeps going until they strike another surface. Since the focus of this article is lens design, we only deal with the case of refraction. In summary, a ray-tracing simulation iterates the following steps:
-
Find the intersection between a ray and a surface
-
Calculate the new traveling direction of a ray
The next sections show how we can do this.
Find the intersection between ray and the object
In geometry, a general way to find the intersections between a ray and a object is to parametrize them. Namely, we can express the vector of the light ray as \(\mathbf{r}(t)=(x(t),y(t),z(t))\) and the equation of the surface as \(S(x,y,z)=0\). Find a \(t\) such that \(S(x(t),y(t),z(t))=0\) and \(x(t),y(t)\) and \(z(t)\) are within the boundary. Let’s say the solution is \(t'\), \(x(t'),y(t')\) and \(z(t')\) are then the intersecton point between the ray and the surface.
\(x(t)\), \(y(t)\) and \(z(t)\) are directional cosines. Geometrical optics often favors the following convention
The starting points of the rays \(x_0\), \(y_0\), \(z_0\) and the initial directional angles \(theta\) and \(phi\) are set by the users as the initial conditions of the rays. These parameters are constant until the ray is reflected or refracted. We can think of \(t\) as the “time of flight” of the ray. The intersection point \(t'\) can be thought of as the time that the ray and the surface intersected. For two-dimensional simulation, we just set \(\phi=0\) and work on \(y-z\) plane only.
Calculate the new traveling direction of a ray
Calculate the normal vector
The normal vector is the normal vector of the tangent vector on the surface \((x,y(x))\). Numerically, the tangent vector of this surface at \((x,y)\) is the first order derivative: \(d\mathbf{s}=(dx,dy)=dx(1,\frac{dy}{dx})=dx(1,y'(x))\). In the case of 2D, the normal vector is \(\mathbf{n}=(dy,-dx)\).
General form of Snell’s law
From high school physics we know that we can calculate the ray defraction by using Snell’s law:
The above equation only describes the relation between the incident angle and refracted angle. To deal with ray vectors incident on an artitrary surface in higher dimenional space, we need a more general expression of Snell’s law:
where \(\mathbf{n}\) is the normal vector of the surface at the point of refraction, \(n_r\) and \(n_r'\) are the refractive index of the mediums, \(\mathbf{r}\) and \(\mathbf{r'}\) are the ray vectors before and after the refraction, respectively. \(\times\) is the vector cross product. Note that all the vector shown above are noramlzed unit vectors. The above equation can be rearranged to obtain a more useful expression for calculating the refracted vector \(\mathbf{r}'\):
and \(\mathbf{r}'\cdot\mathbf{n}\) at the right-hand side can be calculated by using Equation (1)
Substuting the known \(\mathbf{r}\), \(\mathbf{n}\), \(n_r\), \(n_r'\) and \(\mathbf{r}'\cdot\mathbf{n}\) into Equation (2), we can obtain the refracted vector \(\mathbf{r'}\).
References
[1] Roland Winston, Juan C. Minano and Pablo Benitez, Nonimaging Optics. Academic Press, 2005.