Contrary to a pinhole camera, we can instead make the hole a “disc” that has actual radius. Then light rays that go through the disc will be refracted similarly.

However, the difference is that there’s a point where all the refracted rays intersect at a given -value in the scene. That is the focal point, and we can imagine it as a plane that spans that -coordinate. All rays will converge at a single point and sample the same color.

If we move further or closer away, the rays are refracted and are diverging, so they all receive different colors of the geometry at the given focal plane. This is what causes the blur that we see.

Procedure

  1. Cast many rays from the camera to simulate light going through the disc in many locations. To get the ray origin point, we sample and -coordinates on the square, and map them to the circle. We can use concentric disk sampling.
  2. Finally, we have to align the ray with the camera, and move the origin to the camera’s eye: multiply the ray’s origin -components by the camera right and up vector, respectively.
vec3 lens_point = lens_point.x * cam.right + lens_point.y * cam.up + cam.eye;