Fisheye View of Graphics3D Object
I follow the approach suggested by Alex, which was taken from the Mathematica documentation of ImageForwardTransformation. But the required explanation and changes to produce an actual fisheye view are too extensive to be included in a comment, so I write them here.
As mentioned in my comment to Alex's answer, the key is to use as the radial coordinate of the ImageForwardTransformation
the angles between the objects in the scene, as seen from the observer. This would produce the ideal and most common fisheye view, which is the equidistant, or equiangle, fisheye. But other fisheye formulas can be used by simply replacing the angle with a function of angles.
The key is then to obtain angles to the centre of the view for the pixels in a Mathematica image. Mathematica uses standard perspective for which is easy to show (see figure below) that the angles are given by theta = ArcTan[R/d]
.
But to obtain proper angles from the image pixel units one has to consider the definition of ViewPoint
and the bounding box of the Graphics3D
object:
ViewPoint -> {x,y,z}
gives the position of the view point relative to the center of the three‐dimensional box that contains the objects.The view point is given in a special scaled coordinate system in which the longest side of the bounding box has length
1
. The centre of the bounding box is taken to have coordinates{0,0,0}
.
Other key steps for the fisheye view are (i) to place the ViewPoint
orthogonal to the bounding box (two ViewPoint
coordinates have to be zero), (ii) as close as possible (but at a finite distance) to the nearest side of the box and (iii) with ViewAngle -> All
. This will produce an extremely distorted view, for a field of view close to 180 degrees, which can then be remapped into a fisheye view.
The image has to be rasterized at high pixels resolution, to account for the fact that the central part of the distorted image will appear much smaller than the outer parts, due to the large field of view. This, of course, results in a very inefficient procedure. An alternative would be to obtain different views, as Szabolcs suggested in his comments. But this would significantly complicate the procedure.
Following the above steps here is the proposed solution.
I take for illustration the amphitheatre proposed in my original question.
paraboloid[a_, u_, nu_] := {a Sqrt[u] Cos[nu], a Sqrt[u] Sin[nu], u}
a = 5;
h = 20;
gr1 = ParametricPlot3D[paraboloid[a, u, nu], {nu, 0, Pi}, {u, 0, h}];
gr2 = Graphics3D[
Table[Rotate[Cuboid[## - {1, 1, 0}, ## + {1, 1, 2}], nu, {0, 0, 1}, ##]
&[paraboloid[a, u, nu]],
{nu, 0, Pi, Pi/10}, {u, 2, h, 2}]];
Which appears as follow with default viewing parameters
Show[gr1, gr2]
and I show it from a very close distance to the bounding box side and using the full field of view
dist = 0.3;
gr = Show[gr1, gr2, ViewPoint -> {0, -dist, 0}, ViewAngle -> All];
img = Rasterize[gr, RasterSize -> 1000]
This produces the original very distorted (non fisheye) perspective, covering, in this case, a field of view of 169 degrees
This image can be remapped into an equidistant fisheye view, using ImageForwardTransformation
as suggested by Alex, but with a proper fisheye transformation, as follow
f[point_, center_, edgeTan_] := With[
{r = Norm[point - center], ang = ArcTan @@ (point - center), radius = Max[center]},
rnew = radius*ArcTan[edgeTan*r/radius]/ArcTan[edgeTan];
center + rnew*{Cos[ang], Sin[ang]}]
rat = BoxRatios /. AbsoluteOptions[gr, BoxRatios];
ratios = rat/Max @@ rat;
center = ImageDimensions[img]/2;
edgeTan = (0.5 Max @@ ratios[[{1, 3}]])/(dist - 0.5 ratios[[2]]); (* Tan of edge *)
ImageForwardTransformation[img, f[#, center, edgeTan] &, DataRange -> Full]
fov = 2 ArcTan[edgeTan]/Degree (* Image field of view for information *)
This produces the desired equidistant fisheye view, where I show in black the region outside the field of view of the original Mathematica projection
The author wants to see the same scene but in a different perspective, which is called a fisheye. This standard example is in the section ImageForwardTransformation[]
. Reproduced with minor corrections
paraboloid[a_, u_, nu_] := {a Sqrt[u] Cos[nu], a Sqrt[u] Sin[nu], u}
a = 10;
h = 20;
gr1 = ParametricPlot3D[paraboloid[a, u, nu], {nu, 0, Pi}, {u, 0, h},
Axes -> False, Boxed -> False, ImageSize -> 400];
gr2 = Graphics3D[
Table[Rotate[Cuboid[## - {1, 1, 0}, ## + {1, 1, 2}],
nu, {0, 0, 1}, ##] &[paraboloid[a, u, nu]], {nu, 0, Pi,
Pi/20}, {u, 2, h, 2}], Boxed -> False];
im = Show[gr1, gr2, ViewPoint -> {0, -0.5, 0}]
f[x_, y_, c_] :=
With[{r = N@Sqrt[(x - c[[1]])^2 + (y - c[[2]])^2],
t = ArcTan[x - c[[1]], y - c[[2]]], R = Min[c]}, rn = Sqrt[r*R];
{rn*Cos[t] + c[[1]], rn*Sin[t] + c[[2]]}]
ImageForwardTransformation[im, f[#[[1]], #[[2]], {400, 400}/2] &,
DataRange -> Full, Background -> None]