Panda3D
fisheyeLens.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file fisheyeLens.cxx
10  * @author drose
11  * @date 2001-12-12
12  */
13 
14 #include "fisheyeLens.h"
15 #include "deg_2_rad.h"
16 
17 TypeHandle FisheyeLens::_type_handle;
18 
19 // This is the focal-length constant for fisheye lenses. The focal length of
20 // a fisheye lens relates to its fov by the equation:
21 
22 // w = Fdk
23 
24 // Where w is the width of the negative, F is the focal length, and d is the
25 // total field of view in degrees.
26 
27 // k is chosen to make the focal lengths for a fisheye lens roughly correspond
28 // to the equivalent field of view for a conventional, perspective lens. It
29 // was determined empirically by simple examination of a couple of actual
30 // lenses for 35mm film. I don't know how well this extends to other lenses
31 // and other negative sizes.
32 
33 static const PN_stdfloat fisheye_k = 60.0f;
34 // focal_length = film_size * fisheye_k fov;
35 
36 
37 /**
38  * Allocates a new Lens just like this one.
39  */
40 PT(Lens) FisheyeLens::
41 make_copy() const {
42  return new FisheyeLens(*this);
43 }
44 
45 /**
46  * Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is
47  * the center of the lens and (-1,-1) is the lower-left corner, compute the
48  * corresponding vector in space that maps to this point, if such a vector can
49  * be determined. The vector is returned by indicating the points on the near
50  * plane and far plane that both map to the indicated 2-d point.
51  *
52  * The z coordinate of the 2-d point is ignored.
53  *
54  * Returns true if the vector is defined, or false otherwise.
55  */
56 bool FisheyeLens::
57 do_extrude(const Lens::CData *lens_cdata,
58  const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
59  // Undo the shifting from film offsets, etc. This puts the point into the
60  // range [-film_size2, film_size2] in x and y.
61  LPoint3 f = point2d * do_get_film_mat_inv(lens_cdata);
62 
63  // First, get the vector from the center of the film to the point, and
64  // normalize it.
65  LVector2 v2(f[0], f[1]);
66 
67  LPoint3 v;
68 
69  PN_stdfloat r = v2.length();
70  if (r == 0.0f) {
71  // Special case: directly forward.
72  v.set(0.0f, 1.0f, 0.0f);
73 
74  } else {
75  v2 /= r;
76 
77  // Now get the point r units around the circle in the YZ plane.
78  PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
79  PN_stdfloat angle = r * fisheye_k / focal_length;
80  PN_stdfloat sinAngle, cosAngle;
81  csincos(deg_2_rad(angle), &sinAngle, &cosAngle);
82 
83  LVector3 p(0.0, cosAngle, sinAngle);
84 
85  // And rotate this point around the Y axis.
86  v.set(p[0]*v2[1] + p[2]*v2[0],
87  p[1],
88  p[2]*v2[1] - p[0]*v2[0]);
89  }
90 
91  // And we'll need to account for the lens's rotations, etc. at the end of
92  // the day.
93  const LMatrix4 &lens_mat = do_get_lens_mat(lens_cdata);
94  const LMatrix4 &proj_inv_mat = do_get_projection_mat_inv(lens_cdata);
95 
96  near_point = (v * do_get_near(lens_cdata)) * proj_inv_mat * lens_mat;
97  far_point = (v * do_get_far(lens_cdata)) * proj_inv_mat * lens_mat;
98  return true;
99 }
100 
101 /**
102  * Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is
103  * the center of the lens and (-1,-1) is the lower-left corner, compute the
104  * vector that corresponds to the view direction. This will be parallel to
105  * the normal on the surface (the far plane) corresponding to the lens shape
106  * at this point.
107  *
108  * See the comment block on Lens::extrude_vec_impl() for a more in-depth
109  * comment on the meaning of this vector.
110  *
111  * The z coordinate of the 2-d point is ignored.
112  *
113  * Returns true if the vector is defined, or false otherwise.
114  */
115 bool FisheyeLens::
116 do_extrude_vec(const Lens::CData *lens_cdata, const LPoint3 &point2d, LVector3 &vec) const {
117  LPoint3 near_point, far_point;
118  if (!do_extrude(lens_cdata, point2d, near_point, far_point)) {
119  return false;
120  }
121 
122  vec = far_point - near_point;
123 
124  return true;
125 }
126 
127 /**
128  * Given a 3-d point in space, determine the 2-d point this maps to, in the
129  * range (-1,1) in both dimensions, where (0,0) is the center of the lens and
130  * (-1,-1) is the lower-left corner.
131  *
132  * Some lens types also set the z coordinate of the 2-d point to a value in
133  * the range (-1, 1), where -1 represents a point on the near plane, and 1
134  * represents a point on the far plane.
135  *
136  * Returns true if the 3-d point is in front of the lens and within the
137  * viewing frustum (in which case point2d is filled in), or false otherwise.
138  */
139 bool FisheyeLens::
140 do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point2d) const {
141  // First, account for any rotations, etc. on the lens.
142  LVector3 v2 = point3d * do_get_lens_mat_inv(lens_cdata) * do_get_projection_mat(lens_cdata);
143 
144  // A fisheye lens projection has the property that the distance from the
145  // center point to any other point on the projection is proportional to the
146  // actual distance on the sphere along the great circle. Also, the angle to
147  // the point on the projection is equal to the angle to the point on the
148  // sphere.
149 
150  // First, get the straight-line distance from the lens, and use it to
151  // normalize the vector.
152  PN_stdfloat dist = v2.length();
153  v2 /= dist;
154 
155  // Now, project the point into the XZ plane and measure its angle to the Z
156  // axis. This is the same angle it will have to the vertical axis on the
157  // film.
158  LVector2 y(v2[0], v2[2]);
159  y.normalize();
160 
161  if (y == LVector2(0.0f, 0.0f)) {
162  // Special case. This point is either directly ahead or directly behind.
163  point2d.set(0.0f, 0.0f,
164  (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata)));
165  return v2[1] >= 0.0f;
166  }
167 
168  // Now bring the vector into the YZ plane by rotating about the Y axis.
169  LVector2 x(v2[1], v2[0]*y[0]+v2[2]*y[1]);
170 
171  // Now the angle of x to the forward vector represents the distance along
172  // the great circle to the point.
173  PN_stdfloat r = 90.0f - rad_2_deg(catan2(x[0], x[1]));
174 
175  PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
176  PN_stdfloat factor = r * focal_length / fisheye_k;
177 
178  // Compute the depth as a linear distance in the range 0 .. 1.
179  PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
180 
181  point2d.set
182  (y[0] * factor,
183  y[1] * factor,
184  // Z is the distance scaled into the range -1 .. 1.
185  2.0 * z - 1.0
186  );
187 
188  // Now we have to transform the point according to the film adjustments.
189  point2d = point2d * do_get_film_mat(lens_cdata);
190 
191  return
192  point2d[0] >= -1.0f && point2d[0] <= 1.0f &&
193  point2d[1] >= -1.0f && point2d[1] <= 1.0f;
194 }
195 
196 /**
197  * Given a field of view in degrees and a focal length, compute the
198  * correspdonding width (or height) on the film. If horiz is true, this is in
199  * the horizontal direction; otherwise, it is in the vertical direction (some
200  * lenses behave differently in each direction).
201  */
202 PN_stdfloat FisheyeLens::
203 fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool) const {
204  return focal_length * fov / fisheye_k;
205 }
206 
207 /**
208  * Given a field of view in degrees and a width (or height) on the film,
209  * compute the focal length of the lens. If horiz is true, this is in the
210  * horizontal direction; otherwise, it is in the vertical direction (some
211  * lenses behave differently in each direction).
212  */
213 PN_stdfloat FisheyeLens::
214 fov_to_focal_length(PN_stdfloat fov, PN_stdfloat film_size, bool) const {
215  return film_size * fisheye_k / fov;
216 }
217 
218 /**
219  * Given a width (or height) on the film and a focal length, compute the field
220  * of view in degrees. If horiz is true, this is in the horizontal direction;
221  * otherwise, it is in the vertical direction (some lenses behave differently
222  * in each direction).
223  */
224 PN_stdfloat FisheyeLens::
225 film_to_fov(PN_stdfloat film_size, PN_stdfloat focal_length, bool) const {
226  return film_size * fisheye_k / focal_length;
227 }
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
A fisheye lens.
Definition: fisheyeLens.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.