How am I able to perform perspective projection without a near plane? I'm learning about 3D computer graphics, but I'm having a hard time understanding why the near plane of a viewing frustum can not be placed at z position $0$ (right at the camera).

I can understand conceptually that the near plane is essentially the retinal canvas -- so by definition it must exist to some extent -- but I have trouble understanding why the near plane isn't simply an abstract concept where it's actual position is infinitesimally close to the camera position, as opposed to a definite z position away.

In several explanations, the following formula is given to explain why $0$ cannot be used as the near plan position (where $A$ is the camera position, $B$ is an object vertex, and $D$ is the perspective projection of point $B$ onto the near plane):



$${ BC \over AC } = { DE \over AE }$$

In this case, the geometry of similar triangles $ABC$ and $ADE$ is used to determine the height of $D$ via the solution of $DE$. It is obvious that if the near plane is at $0$ ($AE = 0$), then a division by $0$ occurs -- hence, why the near plane cannot be located at position $0$.

However, why is this method used to determine the position of $D$ on the canvas?

I've written a simple raycasting visualizer before and didn't have an explicitly defined near plane. In my engine, I simply defined a $60^\circ$ field of view and divided the number pixels on my screen among that field of view. For example, for a $300$x$300$ screen:

$$1\text{ pixel} = 300/60^\circ = 5^\circ$$

Next, I found the angle between my camera and the object vertex ($\angle BAC$) and divided it by $5^\circ$ to acquire the pixel coordinate on my screen. In this method, no explicit near plane was necessary and I used my actual camera position to determine the angle.

So how was I able to perform a perspective projection without a near plane in my raycasting method?
The near and far planes of a viewing frustum aren't needed for simple 3D→2D projection. What the near and far planes actually do, in a typical rasterizer setup, is define the range of values for the depth buffer. 

Depths in the [near, far] range will be mapped into [0, 1] to be stored in the depth buffer. However, the depths aren't simply linearly rescaled. Instead, we use a hyperbolic mapping for depth: the value stored in the depth buffer is the reciprocal of the actual depth distance, with a scale and offset applied.



If you look at this curve and imagine moving the near plane value toward $z = 0$, the corresponding point on the $1/z$ curve would shoot up toward infinity. The math blows up and the depth buffer becomes useless (it suffers a catastrophic loss of precision).

The reason why we use the reciprocal instead of some other function of depth is basically convenience: the reciprocal depth interpolates nicely in screen space, and it fits naturally into the mathematical framework of perspective projections: there's already a divide by $z$ being applied to the $x, y$ coordinates.

If you'd like to know more, I have a short article on the topic: Depth Precision Visualized.