Anamorphic rendering from the reflection on a spherical mirror

A short memo for myself on how to render an image from a reflection on a spherical mirror.

Inspiration from this video by FrostKiwi.

Given a square input image of the reflection of a scene on a spherical mirror, one can reconstruct an output image of the scene as seen from a pinhole camera located at the center of that spherical mirror if we make the assumption that the image of the spherical mirror has taken been by an orthographic camera. Under that assumption, the calculation of the pixel coordinate in the input image for any given vector is simple and described below. Then, the view vector for the pinhole camera for each pixel of the output image can be mapped to a pixel in the input image, and the scene viewed from the pinhole camera can be easily calculated.

The calculation of the pixel coordinate \(\vec{p}\) in the input image for a given unit view vector \(\vec{r}\) is based on the formula for reflection of light: $$ \vec{r}=\vec{i}-2(\vec{n}.\vec{i})\vec{n} $$ where \(\vec{r}\) is the reflected direction, \(\vec{n}\) is the normal to the surface of the spherical mirror at the incident point and \(\vec{i}\) is the incident direction (i.e. the view vector for the orthographic camera of the input image).

Under the assumption of orthography for the input image, \(\vec{i}=\vec{(0,0,1)}\), \(p_x=I(n_x)\) and \(p_y=I(n_y)\), where \(I()\) scales and translates appropriately from the input image coordinates to the spherical mirror coordinates considered to be a unit sphere centered at the origin. To get \(\vec{p}\) in function of \(\vec{r}\), we then need to calculate \(\vec{n}\) in function of \(\vec{r}\), in other word the inverse of the reflection formula. $$ \vec{r}= \vec{(0,0,1)}-2(\vec{n}.\vec{(0,0,1)})\vec{n} $$ equivalent to $$ \left\lbrace\begin{array}{l} r_x=-2n_zn_x\\ r_y=-2n_zn_y\\ r_z=1-2n_z^2\\ \end{array}\right. $$ then $$ \left\lbrace\begin{array}{l} n_x=\frac{1}{-2n_z}r_x\\ n_y=\frac{1}{-2n_z}r_y\\ n_z=\sqrt{\frac{1-r_z}{2}}\\ \end{array}\right. $$ equivalent to $$ \left\lbrace\begin{array}{l} n_x=\frac{1}{-2\sqrt{\frac{1-r_z}{2}}}r_x\\ n_y=\frac{1}{-2\sqrt{\frac{1-r_z}{2}}}r_y\\ \end{array}\right. $$ which simplifies to $$ \left\lbrace\begin{array}{l} n_x=\frac{-1}{\sqrt{2(1-r_z)}}r_x\\ n_y=\frac{-1}{\sqrt{2(1-r_z)}}r_y\\ \end{array}\right. $$ and finally we get \(\vec{p}\) in function of \(\vec{r}\) $$ \left\lbrace\begin{array}{l} p_x=I^{-1}(\frac{-1}{\sqrt{2(1-r_z)}}r_x)\\ p_y=I^{-1}(\frac{-1}{\sqrt{2(1-r_z)}}r_y)\\ \end{array}\right. $$

How to use it in pseudocode:

Edge case to take care of: if v.z equals to -1 you get a NaN (that's when you're trying look behind the sphere, any point at the edge of the image of the sphere correspond to the reflected direction, hence the result is undefined).

FrostKiwi also explains how to correct for the fact that the input image is probably not taken with an orthographic camera. One can add a correction coefficient with an ad-hoc value to correct the distortion. The formula then becomes: $$ \left\lbrace\begin{array}{l} p_x=I^{-1}(\frac{-1}{\sqrt{2(1-r_z)}sin(\alpha)}r_x)\\ p_y=I^{-1}(\frac{-1}{\sqrt{2(1-r_z)}sin(\alpha)}r_y)\\ \end{array}\right. $$ where \(\alpha\in]0,\pi/2]\).

Demo video of the result available here.