Formula:
nearPlane = nearestApproachToPlayer / sqrt(1 + tan(fov/2)2 · (aspectRatio2 + 1)))
JavaScript code:
var nearPlane = nearestApproachToPlayer
/ Math.sqrt(1 + Math.pow(Math.tan(fov/180*Math.PI/2), 2)
* (Math.pow(aspectRatio, 2) + 1));
Derivation:
Geometrically, consider the pyramid whose base is the near clip plane and tip is the origin. Let nearPlane be the height of the pyramid, and w and h the width and height of the pyramid's base.
w = aspectRatio · h
The FOV determines the slope of the height-axis sides of the pyramid:
slope = tan(fov/2)
⇓
h/nearPlane = 2 tan(fov/2)
⇓
h/2 = nearPlane tan(fov/2)
Any corner point of the near clip plane is offset from the center of the clip plane by (w/2, h/2), so the distance is sqrt((w/2)2 + (h/2)2). The distance from the origin of this corner point is the hypotenuse of the right triangle formed by nearPlane and the former distance, so is sqrt((w/2)2 + (h/2)2 + nearPlane2).
We want that distance to the corner point to be equal to the closest approach of any geometry.
nearestApproachToPlayer = sqrt((w/2)2 + (h/2)2 + nearPlane2)
Applying straightforward algebra produces the formula given above.
I have not checked my algebra, but I have empirically tested the formula: if I multiply nearPlane by 1.1, then it produces a clip plane which is just a bit too far, for various aspect ratios. I have not tried different FOVs than 60°.