Panda3D
perspectiveLens.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 perspectiveLens.cxx
10  * @author drose
11  * @date 1999-02-18
12  */
13 
14 #include "perspectiveLens.h"
15 #include "bamReader.h"
16 
17 TypeHandle PerspectiveLens::_type_handle;
18 
19 
20 /**
21  * Allocates a new Lens just like this one.
22  */
23 PT(Lens) PerspectiveLens::
24 make_copy() const {
25  return new PerspectiveLens(*this);
26 }
27 
28 /**
29  * Returns true if the lens represents a linear projection (e.g.
30  * PerspectiveLens, OrthographicLens), and therefore there is a valid matrix
31  * returned by get_projection_mat(), or false otherwise.
32  */
34 is_linear() const {
35  return true;
36 }
37 
38 /**
39  * Returns true if the lens represents a perspective projection (i.e. it is a
40  * PerspectiveLens), false otherwise.
41  */
43 is_perspective() const {
44  return true;
45 }
46 
47 /**
48  * This is the generic implementation, which is based on do_extrude() and
49  * assumes a linear distribution of depth values between the near and far
50  * points.
51  */
52 bool PerspectiveLens::
53 do_extrude_depth(const CData *cdata,
54  const LPoint3 &point2d, LPoint3 &point3d) const {
55  return do_extrude_depth_with_mat(cdata, point2d, point3d);
56 }
57 
58 /**
59  * Computes the complete transformation matrix from 3-d point to 2-d point, if
60  * the lens is linear.
61  */
62 void PerspectiveLens::
63 do_compute_projection_mat(Lens::CData *lens_cdata) {
64  CoordinateSystem cs = lens_cdata->_cs;
65  if (cs == CS_default) {
66  cs = get_default_coordinate_system();
67  }
68 
69  PN_stdfloat fl = do_get_focal_length(lens_cdata);
70  PN_stdfloat fFar = do_get_far(lens_cdata);
71  PN_stdfloat fNear = do_get_near(lens_cdata);
72  PN_stdfloat a, b;
73 
74  // Take the limits if either near or far is infinite.
75  if (cinf(fFar)) {
76  a = 1;
77  b = -2 * fNear;
78  } else if (cinf(fNear)) {
79  // This is valid if the near/far planes are inverted.
80  a = -1;
81  b = 2 * fFar;
82  } else {
83  PN_stdfloat far_minus_near = fFar-fNear;
84  a = (fFar + fNear);
85  b = -2 * fFar * fNear;
86  a /= far_minus_near;
87  b /= far_minus_near;
88  }
89 
90  LMatrix4 canonical;
91  switch (cs) {
92  case CS_zup_right:
93  canonical.set( fl, 0.0f, 0.0f, 0.0f,
94  0.0f, 0.0f, a, 1.0f,
95  0.0f, fl, 0.0f, 0.0f,
96  0.0f, 0.0f, b, 0.0f);
97  break;
98 
99  case CS_yup_right:
100  canonical.set( fl, 0.0f, 0.0f, 0.0f,
101  0.0f, fl, 0.0f, 0.0f,
102  0.0f, 0.0f, -a, -1.0f,
103  0.0f, 0.0f, b, 0.0f);
104  break;
105 
106  case CS_zup_left:
107  canonical.set( fl, 0.0f, 0.0f, 0.0f,
108  0.0f, 0.0f, -a, -1.0f,
109  0.0f, fl, 0.0f, 0.0f,
110  0.0f, 0.0f, b, 0.0f);
111  break;
112 
113  case CS_yup_left:
114  canonical.set( fl, 0.0f, 0.0f, 0.0f,
115  0.0f, fl, 0.0f, 0.0f,
116  0.0f, 0.0f, a, 1.0f,
117  0.0f, 0.0f, b, 0.0f);
118  break;
119 
120  default:
121  gobj_cat.error()
122  << "Invalid coordinate system " << (int)cs << " in PerspectiveLens!\n";
123  canonical = LMatrix4::ident_mat();
124  }
125 
126  lens_cdata->_projection_mat = do_get_lens_mat_inv(lens_cdata) * canonical * do_get_film_mat(lens_cdata);
127 
128  if ((lens_cdata->_user_flags & UF_interocular_distance) == 0) {
129  lens_cdata->_projection_mat_left = lens_cdata->_projection_mat_right = lens_cdata->_projection_mat;
130 
131  } else {
132  // Compute the left and right projection matrices in case this lens is
133  // assigned to a stereo DisplayRegion.
134 
135  LVector3 iod = lens_cdata->_interocular_distance * 0.5f * LVector3::left(lens_cdata->_cs);
136  lens_cdata->_projection_mat_left = do_get_lens_mat_inv(lens_cdata) * LMatrix4::translate_mat(-iod) * canonical * do_get_film_mat(lens_cdata);
137  lens_cdata->_projection_mat_right = do_get_lens_mat_inv(lens_cdata) * LMatrix4::translate_mat(iod) * canonical * do_get_film_mat(lens_cdata);
138 
139  if ((lens_cdata->_user_flags & UF_convergence_distance) != 0 &&
140  !cinf(lens_cdata->_convergence_distance)) {
141  nassertv(lens_cdata->_convergence_distance != 0.0f);
142  LVector3 cd;
143  if (stereo_lens_old_convergence) { // The old, incorrect calculation was requested.
144  cd = (0.25f / lens_cdata->_convergence_distance) * LVector3::left(lens_cdata->_cs);
145  } else {
146  const LVecBase2 &fov = do_get_fov(lens_cdata);
147  cd = (2.0f / fov_to_film(fov[0], lens_cdata->_convergence_distance, true)) * iod;
148  }
149  lens_cdata->_projection_mat_left *= LMatrix4::translate_mat(cd);
150  lens_cdata->_projection_mat_right *= LMatrix4::translate_mat(-cd);
151  }
152  }
153 
154  do_adjust_comp_flags(lens_cdata,
155  CF_projection_mat_inv | CF_projection_mat_left_inv | CF_projection_mat_right_inv,
156  CF_projection_mat);
157 }
158 
159 /**
160  * Given a field of view in degrees and a focal length, compute the
161  * correspdonding width (or height) on the film. If horiz is true, this is in
162  * the horizontal direction; otherwise, it is in the vertical direction (some
163  * lenses behave differently in each direction).
164  */
165 PN_stdfloat PerspectiveLens::
166 fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool) const {
167  return (ctan(deg_2_rad(fov * 0.5f)) * focal_length) * 2.0f;
168 }
169 
170 /**
171  * Given a field of view in degrees and a width (or height) on the film,
172  * compute the focal length of the lens. If horiz is true, this is in the
173  * horizontal direction; otherwise, it is in the vertical direction (some
174  * lenses behave differently in each direction).
175  */
176 PN_stdfloat PerspectiveLens::
177 fov_to_focal_length(PN_stdfloat fov, PN_stdfloat film_size, bool) const {
178  return film_size * 0.5f / ctan(deg_2_rad(fov * 0.5f));
179 }
180 
181 /**
182  * Given a width (or height) on the film and a focal length, compute the field
183  * of view in degrees. If horiz is true, this is in the horizontal direction;
184  * otherwise, it is in the vertical direction (some lenses behave differently
185  * in each direction).
186  */
187 PN_stdfloat PerspectiveLens::
188 film_to_fov(PN_stdfloat film_size, PN_stdfloat focal_length, bool) const {
189  return rad_2_deg(catan(film_size * 0.5f / focal_length)) * 2.0f;
190 }
191 
192 /**
193  * Tells the BamReader how to create objects of type Lens.
194  */
197  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
198 }
199 
200 /**
201  * This function is called by the BamReader's factory when a new object of
202  * type Lens is encountered in the Bam file. It should create the Lens and
203  * extract its information from the file.
204  */
205 TypedWritable *PerspectiveLens::
206 make_from_bam(const FactoryParams &params) {
207  PerspectiveLens *lens = new PerspectiveLens;
208  DatagramIterator scan;
209  BamReader *manager;
210 
211  parse_params(params, scan, manager);
212  lens->fillin(scan, manager);
213 
214  return lens;
215 }
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
PT(Lens) PerspectiveLens
Allocates a new Lens just like this one.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
virtual bool is_linear() const
Returns true if the lens represents a linear projection (e.g.
virtual bool is_perspective() const
Returns true if the lens represents a perspective projection (i.e.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A perspective-type lens: a normal camera.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Lens.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81