We all know the thin lens equation. For $o$ being a horizontal object distance and $f$ being the focal length, the horizontal image distance $i$ is described by:

$$\frac{1}{f} = \frac{1}{o} + \frac{1}{i}$$

However, I haven't seen this applied to determine where an incoming ray should go. This is a problem when writing, for example, a ray tracer.

Working it out seemed to be pretty straightforward. I reasoned that the above equation gives a location of an image point that any object point focuses to. Therefore, if you consider an incoming ray starting at some position $\vec{p}_1$, then we can consider $\vec{p}_1$ to be some "object" and figure out where its image is. Since by definition the object point focuses to the image point, by definition every ray from the object point through the lens passes through the image. Therefore, you can just take the incoming ray's intersection with the lens, and then shoot a new ray from that point out through the image.

In math, that looks like (feel free to skip) this. Let's assume everything is in 2D and that the ray is entering from the left and hits a thin lens centered at the origin. Ray $\vec{R}_1(s)=\vec{p}_1+s\cdot\vec{d}_1$ is the incoming ray and we want to find $\vec{p}_2$, $\vec{d}_2$ for outgoing ray $\vec{R}_2(t)=\vec{p}_2+t\cdot\vec{d}_2$. Finding $\vec{p}_2$ is simple, since this is just the intersection of $\vec{R}_1$ with the lens. To find $\vec{d}_2$, first we find an "image" of the ray's origin, $\vec{I}$: $$o = |\vec{p}_{1,x}|\tag{horizontal distance}$$ $$i = \left( \frac{1}{f} - \frac{1}{o} \right)^{-1} \tag{thin lens eq.}$$ $$\vec{I} = -\frac{i}{o} \vec{p}_{1} \tag{scale through lens}$$

Note that the above works regardless of whether the ray origin $\vec{p}_1$ is inside the focal distance or not. For the next step, it matters, though. If the image is real (i.e., on the opposite side of the lens from the incoming ray): $$\vec{d}_2 = \frac{\vec{I}_{real} - \vec{p}_2}{|| \vec{I}_{real} - \vec{p}_2 ||}$$ If the image is virtual (i.e., on the same side of the lens as the incoming ray), then the concept is the same; you just need to reverse the direction: $$\vec{d}_2 = \frac{\vec{p}_2 - \vec{I}_{virtual}}{|| \vec{p}_2 - \vec{I}_{virtual} ||}$$

Note that all of the above works regardless of which side the ray enters on (so we can relax the constraint about the ray coming from the left).

All of this makes nice pseudocode (originally from Python) (takes into account a lens center and a few edge cases):

o = [(positive) horizontal distance from ray origin to lens center]
lens_to_obj = [ray origin] - [lens center]
lens_to_objn = normalized(lens_to_obj)
if o == [focal length]:
    #Object is exactly at the focal length; rays are parallel and no finite image is formed.
    new_direction = -lens_to_objn
    #Thin lens equation
    i = 1.0 / (1.0/[focal length] - 1.0/o)
    if o < [focal length]:
        #Object is inside the focal length; rays diverge and virtual image is behind object
        #   on the same side of the lens.
        image = (-i/o)*lens_to_obj + [lens center]
        new_direction = normalized([lens hit pt] - image)
        #Object is outside the focal length; rays converge and real image is on the other
        #   side of the lens.
        image = (i/-o)*lens_to_obj + [lens center]
        new_direction = normalized(image - [lens hit pt])
return Ray([lens hit pt], new_direction)

When I use this code in a raytracer, I get nice looking images, but Monte Carlo integrals running forward and backward don't agree (in a way that they actually do for other kinds of lenses (for example, I tried a glass sphere)). Have some eye candy:flux integrals agree with an aperture flux integrals disagree with a thin lens

In the above, the first picture is of an aperture; note how the flux estimates agree. The second picture is of a thin lens; note how they don't. The 275 line, well commented source that generated the above is available here.

The point of this very long question is this: something has gone wrong with these flux calculations. Under the circumstances, I'd say it's something else, but retrying these experiments with other kinds of distorting objects (e.g. mirrored/glass circles) shows that the problem really only seems to be occurring with thin lenses. So, my question is this: What's wrong with the above algorithm for computing refracted rays?


closed as off-topic by Qmechanic Sep 19 '14 at 11:39

  • This question does not appear to be about physics within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

  • $\begingroup$ This question appears to be off-topic. $\endgroup$ – Qmechanic Sep 19 '14 at 11:39
  • $\begingroup$ @Qmechanic: to clarify, I'm trying to ask what is physically invalid about the above model. I've shown my derivation, but for some reason the result is not physically accurate. $\endgroup$ – imallett Sep 21 '14 at 20:06
  • $\begingroup$ I suspect the problem lies in the fact that in some places you hard code "left to right" as the direction of the ray, rather than "towards the lens" or "away from it". If you write your code correctly, then swapping object and image should lead to exactly the same equations. If I understand what you are saying, your implementation does not - which is why it works in the forward direction but not the reverse direction. If well written, it should not even need an "if" statement anywhere... $\endgroup$ – Floris Oct 5 '14 at 19:25

You're unlikely to get help here because yours is a detailed debugging exercise: its something that the writer of the code is in the best position to do. Most ray tracers don't use the thin lens formula at all: they encode Snell's law and assume functional forms for the lens surface. The point of intersection with the surface is then calculated (this can be done analytically even in 3D) if the surface is spherical or a plane, a numerical method like bisection is needed for a general, aspherical surface. Once the point of intersection is found, Snell's law is applied and then you have a new ray defined by the same intersection position and the new direction found by Snell's law (a line is fully defined by its direction and any point on it).

I would suggest, if you're serious about this stuff, writing another tracer grounded on the algorithm I have just described - or at least something independent of your algorithm. You can then see where points of intersection are calculated to be and what the ray directions are found to be by both methods and compare the two step by step. Eventually, you will have debugged both algorithms.


Not the answer you're looking for? Browse other questions tagged or ask your own question.