OSVR-Core
ProjectionMatrix.h
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_ProjectionMatrix_h_GUID_638B5832_DF1C_4BB7_9844_BF9810926107
26 #define INCLUDED_ProjectionMatrix_h_GUID_638B5832_DF1C_4BB7_9844_BF9810926107
27 
28 // Internal Includes
29 #include <osvr/Util/Rect.h>
31 
32 // Library/third-party includes
33 // - none
34 
35 // Standard includes
36 #include <type_traits>
37 
38 namespace osvr {
39 namespace util {
48  inline Eigen::Matrix4d createProjectionMatrix(Rectd const &bounds,
49  double near, double far) {
50  // Convert from "left, right, bottom top, near, far" to the 4x4
51  // transform.
52  // See https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml
53  // BEGIN APPARENTLY OUTDATED NOTE - works more accurately if you ignore
54  // that.
55  // NOTE: There is actually a bug in the documentation. If you
56  // call glFrustum() and print out the results and compare them,
57  // the value D from that page holds -1 and the value where there
58  // is a -1 is what holds D. This error is also copied to the
59  // Microsoft page describing this function. These are elements
60  // [2][3] and [3][2], which are swapped.
61  // END APPARENTLY OUTDATED NOTE
62  auto const right = bounds[Rectd::RIGHT];
63  auto const left = bounds[Rectd::LEFT];
64  auto const top = bounds[Rectd::TOP];
65  auto const bottom = bounds[Rectd::BOTTOM];
66 
67  Eigen::Matrix4d mat;
68  // clang-format off
69  mat << (2 * near / (right - left)), 0, ((right + left) / (right - left)), 0,
70  0, (2 * near / (top - bottom)), ((top + bottom) / (top - bottom)), 0,
71  0, 0, (-(far + near) / (far - near)), (-2 * far * near / (far - near)),
72  0, 0, -1, 0;
73  // clang-format on
74  return mat;
75  }
76 
77  namespace projection_options {
78 
81  enum OptMasks { ZOutputUnsignedBit = 0x1, LeftHandedInputBit = 0x2 };
82 
86  enum OptBits {
87  ZOutputSigned = 0,
88  ZOutputUnsigned = ZOutputUnsignedBit,
89 
90  RightHandedInput = 0,
91  LeftHandedInput = LeftHandedInputBit
92  };
93 
94  typedef unsigned char OptionType;
95  template <OptionType Options, OptionType Bit>
96  using CheckOptionBit =
97  std::integral_constant<bool,
98  static_cast<bool>(0 != (Options & Bit))>;
99 
100  template <OptionType Options>
101  using IsZOutputUnsigned = CheckOptionBit<Options, ZOutputUnsignedBit>;
102  template <OptionType Options>
103  using IsLeftHandedInput = CheckOptionBit<Options, LeftHandedInputBit>;
104 
105  } // namespace projection_options
106 
107  namespace projection_detail {
108  // 33 and 34 for signed Z output (range of [-1, 1])
109  template <projection_options::OptionType options,
110  bool = projection_options::IsZOutputUnsigned<options>::value>
111  struct ThirdRow {
112  static inline double get3(double near, double far) {
113  return (-(far + near) / (far - near));
114  }
115  static inline double get4(double near, double far) {
116  return (-2 * far * near / (far - near));
117  }
118  };
119  // 33 and 34 for unsigned Z output (range of [0, 1])
120  template <projection_options::OptionType options>
121  struct ThirdRow<options, true> {
122  static inline double get3(double near, double far) {
123  return (-far / (far - near));
124  }
125  static inline double get4(double near, double far) {
126  return (-far * near / (far - near));
127  }
128  };
129  template <projection_options::OptionType options>
130  inline double get33(double near, double far) {
131  return ThirdRow<options>::get3(near, far);
132  };
133  template <projection_options::OptionType options>
134  inline double get34(double near, double far) {
135  return ThirdRow<options>::get4(near, far);
136  }
139  template <projection_options::OptionType options, typename = void>
141  static void apply(Eigen::Matrix4d &) {}
142  };
144  template <projection_options::OptionType options>
146  options,
147  typename std::enable_if<
148  projection_options::IsLeftHandedInput<options>::value>::type> {
149  static void apply(Eigen::Matrix4d &mat) { mat.col(2) *= -1.; }
150  };
151  } // namespace projection_detail
157  template <projection_options::OptionType options =
158  projection_options::ZOutputSigned |
159  projection_options::RightHandedInput>
160  inline Eigen::Matrix4d
161  parameterizedCreateProjectionMatrix(Rectd const &bounds, double near,
162  double far) {
163  // Convert from "left, right, bottom top, near, far" to the 4x4
164  // transform.
165  // See https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml
166  // BEGIN APPARENTLY OUTDATED NOTE - works accurately if you ignore it
167  // NOTE: There is actually a bug in the documentation. If you
168  // call glFrustum() and print out the results and compare them,
169  // the value D from that page holds -1 and the value where there
170  // is a -1 is what holds D. This error is also copied to the
171  // Microsoft page describing this function. These are elements
172  // [2][3] and [3][2], which are swapped.
173  // END APPARENTLY OUTDATED NOTE
174  auto right = bounds[Rectd::RIGHT];
175  auto left = bounds[Rectd::LEFT];
176  auto top = bounds[Rectd::TOP];
177  auto bottom = bounds[Rectd::BOTTOM];
178 
179  // These two methods encapsulate the difference between signed-Z and
180  // unsigned-Z.
181  using projection_detail::get33;
182  using projection_detail::get34;
183  Eigen::Matrix4d mat;
184  // clang-format off
185  mat << (2 * near / (right - left)), 0, ((right + left) / (right - left)), 0,
186  0, (2 * near / (top - bottom)), ((top + bottom) / (top - bottom)), 0,
187  0, 0, get33<options>(near, far), get34<options>(near, far),
188  0, 0, -1, 0;
189  // clang-format on
190 
191  // If the options specify a left-handed input, this function call will
192  // modify the matrix. If not, it turns into an empty call to be
193  // optimized out.
196  return mat;
197  }
198 } // namespace util
199 } // namespace osvr
200 #endif // INCLUDED_ProjectionMatrix_h_GUID_638B5832_DF1C_4BB7_9844_BF9810926107
Definition: RunLoopManager.h:42
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
Definition: TypeSafeIdHash.h:44
Definition: ProjectionMatrix.h:111
Header wrapping include of <Eigen/Core> and <Eigen/Geometry> for warning quieting.
Eigen::Matrix4d parameterizedCreateProjectionMatrix(Rectd const &bounds, double near, double far)
Takes in points at the near clipping plane, as well as the near and far clipping planes.
Definition: ProjectionMatrix.h:161
typename F::template apply< Args... > apply
Apply an alias class.
Definition: Apply.h:44
OptBits
The flags (combine with bitwise-or |) for specifying configuration - do not depend on these being equ...
Definition: ProjectionMatrix.h:86
Definition: Rect.h:39
Adjustment needed for left-handed input: dummy case of not requesting left-hand input.
Definition: ProjectionMatrix.h:140
Header.
Eigen::Matrix4d createProjectionMatrix(Rectd const &bounds, double near, double far)
Takes in points at the near clipping plane, as well as the near and far clipping planes.
Definition: ProjectionMatrix.h:48
OptMasks
The bit masks for testing conditions - do not depend on these being equal to a given enum value of Op...
Definition: ProjectionMatrix.h:81
Definition: osvr_print_tree.cpp:52