I'm curious if a shader can be made for a flat square that can act as an optical lens. In the shader be able to set a f factor, to set focus strength distance.

  • $\begingroup$ Can it be a thin cube instead of a square? $\endgroup$ – K. A. Buhr Nov 21 '19 at 1:20

I guess the answer is yes, if you don't mind having a solidify modifier on the square to create a thin square plate. The idea is to use a Glass BSDF with a network of nodes to calculate normals mimicking the curved surfaces of a real lens.

Specifically, if you have a solidified x-y plane and the camera is looking from the positive z-axis, the normal of the close face is pointing at (0,0,1), and the normal of the far face is pointing at (0,0,-1). If you adjust the normal at each (x,y) point so that it points outward from the lens center on the close face, in the direction (c*x,c*y,1) and also outward from the lens center on the far face, in the direction (c*x,c*y,-1) for some value c (possibly depending on x and y), that should mimic a convex lens.

While it's far from obvious, it turns out that using a fixed value for c for all (x,y) gives a good approximation for a thin spherical lens that isn't too big relative to its focal length. In fact, I think this "approximation" has less spherical aberration than a real spherical lens. For glass with IOR=1.5, we will have approximately c=1/f for f the focal length.

The node network is a little more complex than this would suggest, because the "Normal" output of the "Geometry" node and the "Normal" input of the "Glass BSDF" node are in world coordinates, and we need to do our calculations in object coordinates. Also, for the far face, the normal that the shader sees is not the usual normal pointing away from the viewer, but rather the flipped normal on the back surface of the face, so we have to consult Geometry->Backfacing to make sure we are adding the correction in the right direction to make both faces convex.

The full node network looks like this:

enter image description here

Some important notes on using it:

  • It should be applied to a solid object with two flat parallel faces placed close together, like a plane with the Solidify modifier.
  • The plates must be in the x-y plane. If the object is rotated, the rotation should not be applied. The lens won't work unless the normals of the lens faces lie along the object z-axis.
  • The input focal length (where 0.15 = 150mm) will be scale-correct only if the scale of the object is 1, so you should apply the object scale. As an alternative to creating a new material for every focal length, you can use object scale to adjust the actual focal length relative to the focal length in the material.
  • To adjust the actual size of the lens without changing its focal length --i.e., to set the f-stop-- just scale the lens in edit mode.

I have a 2.81-compatible .blend file attached at the bottom; sorry, but it just crashes on 2.80 or earlier. The "FakeLens" material is a cleaned up version of the node network above. Switch on the rendered view, and you should see three lenses like this:

enter image description here

The circular lens on the right is a true curved lens made from two slices of a sphere and using a pure Glass BSDF material. The lens in the middle is a square with a Solidify modifier using FakeLens, and the lens on the left is a thin cube using FakeLens.

Here's the 2.81-only file:

  • 1
    $\begingroup$ Great answer well explained $\endgroup$ – user219279 Nov 24 '19 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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