ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FilamentCamera.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 // 4068: Filament has some clang-specific vectorizing pragma's that MSVC flags
11 #ifdef _MSC_VER
12 #pragma warning(push)
13 #pragma warning(disable : 4068)
14 #endif // _MSC_VER
15 
16 #include <filament/Camera.h>
17 #include <filament/Engine.h>
18 #include <math/mat4.h> // necessary for mat4f
19 
20 // Necessary for filament::utils::EntityManager::get(), replace with
21 // engine_.getEntityManager() for Filament 1.9.23+
22 #include <utils/EntityManager.h>
23 
24 #ifdef _MSC_VER
25 #pragma warning(pop)
26 #endif // _MSC_VER
27 
28 namespace cloudViewer {
29 namespace visualization {
30 namespace rendering {
31 
32 namespace {
33 Camera::Transform FilamentToCameraTransform(const filament::math::mat4& ft) {
34  Camera::Transform::MatrixType m;
35  m << float(ft(0, 0)), float(ft(0, 1)), float(ft(0, 2)), float(ft(0, 3)),
36  float(ft(1, 0)), float(ft(1, 1)), float(ft(1, 2)), float(ft(1, 3)),
37  float(ft(2, 0)), float(ft(2, 1)), float(ft(2, 2)), float(ft(2, 3)),
38  float(ft(3, 0)), float(ft(3, 1)), float(ft(3, 2)), float(ft(3, 3));
39 
40  return Camera::Transform(m);
41 }
42 
43 Camera::Transform FilamentToCameraTransform(const filament::math::mat4f& ft) {
44  Camera::Transform::MatrixType m;
45 
46  m << ft(0, 0), ft(0, 1), ft(0, 2), ft(0, 3), ft(1, 0), ft(1, 1), ft(1, 2),
47  ft(1, 3), ft(2, 0), ft(2, 1), ft(2, 2), ft(2, 3), ft(3, 0),
48  ft(3, 1), ft(3, 2), ft(3, 3);
49 
50  return Camera::Transform(m);
51 }
52 
53 filament::math::mat4f CameraToFilamentTransformF(const Camera::Transform& t) {
54  auto e_matrix = t.matrix();
55  return filament::math::mat4f(filament::math::mat4f::row_major_init{
56  e_matrix(0, 0), e_matrix(0, 1), e_matrix(0, 2), e_matrix(0, 3),
57  e_matrix(1, 0), e_matrix(1, 1), e_matrix(1, 2), e_matrix(1, 3),
58  e_matrix(2, 0), e_matrix(2, 1), e_matrix(2, 2), e_matrix(2, 3),
59  e_matrix(3, 0), e_matrix(3, 1), e_matrix(3, 2), e_matrix(3, 3)});
60 }
61 
62 } // namespace
63 
64 FilamentCamera::FilamentCamera(filament::Engine& engine) : engine_(engine) {
65  camera_entity_ = utils::EntityManager::get().create();
66  camera_ = engine_.createCamera(camera_entity_);
67  projection_.is_ortho = false;
68  projection_.is_intrinsic = false;
69 }
70 
72  engine_.destroyCameraComponent(camera_entity_);
73  engine_.destroy(camera_entity_);
74  camera_entity_.clear();
75 }
76 
77 void FilamentCamera::CopyFrom(const Camera* camera) {
78  SetModelMatrix(camera->GetModelMatrix());
79 
80  auto& proj = camera->GetProjection();
81  if (proj.is_ortho) {
82  SetProjection(proj.proj.ortho.projection, proj.proj.ortho.left,
83  proj.proj.ortho.right, proj.proj.ortho.bottom,
84  proj.proj.ortho.top, proj.proj.ortho.near_plane,
85  proj.proj.ortho.far_plane);
86  } else if (proj.is_intrinsic) {
87  Eigen::Matrix3d intrinsic_matrix;
88  intrinsic_matrix.setIdentity();
89  intrinsic_matrix(0, 0) = proj.proj.intrinsics.fx;
90  intrinsic_matrix(1, 1) = proj.proj.intrinsics.fy;
91  intrinsic_matrix(0, 2) = proj.proj.intrinsics.cx;
92  intrinsic_matrix(1, 2) = proj.proj.intrinsics.cy;
93  SetProjection(intrinsic_matrix, proj.proj.intrinsics.near_plane,
94  proj.proj.intrinsics.far_plane,
95  proj.proj.intrinsics.width, proj.proj.intrinsics.height);
96  } else {
97  SetProjection(proj.proj.perspective.fov, proj.proj.perspective.aspect,
98  proj.proj.perspective.near_plane,
99  proj.proj.perspective.far_plane,
100  proj.proj.perspective.fov_type);
101  }
102 }
103 
105  double fov, double aspect, double near, double far, FovType fov_type) {
106  if (aspect > 0.0) {
107  filament::Camera::Fov dir = (fov_type == FovType::Horizontal)
108  ? filament::Camera::Fov::HORIZONTAL
109  : filament::Camera::Fov::VERTICAL;
110 
111  camera_->setProjection(fov, aspect, near, far, dir);
112 
113  projection_.is_ortho = false;
114  projection_.is_intrinsic = false;
115  projection_.proj.perspective.fov_type = fov_type;
116  projection_.proj.perspective.fov = fov;
117  projection_.proj.perspective.aspect = aspect;
118  projection_.proj.perspective.near_plane = near;
119  projection_.proj.perspective.far_plane = far;
120  }
121 }
122 
124  double left,
125  double right,
126  double bottom,
127  double top,
128  double near,
129  double far) {
130  filament::Camera::Projection proj =
131  (projection == Projection::Ortho)
132  ? filament::Camera::Projection::ORTHO
133  : filament::Camera::Projection::PERSPECTIVE;
134 
135  camera_->setProjection(proj, left, right, bottom, top, near, far);
136 
137  projection_.is_ortho = true;
138  projection_.is_intrinsic = false;
139  projection_.proj.ortho.projection = projection;
140  projection_.proj.ortho.left = left;
141  projection_.proj.ortho.right = right;
142  projection_.proj.ortho.bottom = bottom;
143  projection_.proj.ortho.top = top;
144  projection_.proj.ortho.near_plane = near;
145  projection_.proj.ortho.far_plane = far;
146 }
147 
148 void FilamentCamera::SetProjection(const Eigen::Matrix3d& intrinsics,
149  double near,
150  double far,
151  double width,
152  double height) {
153  filament::math::mat4 custom_proj;
154  custom_proj[0][0] = 2.0 * intrinsics(0, 0) / width;
155  custom_proj[0][1] = 0.0;
156  custom_proj[0][2] = 0.0;
157  custom_proj[0][3] = 0.0;
158 
159  custom_proj[1][0] = 0.0;
160  custom_proj[1][1] = 2.0 * intrinsics(1, 1) / height;
161  custom_proj[1][2] = 0.0;
162  custom_proj[1][3] = 0.0;
163 
164  custom_proj[2][0] = 1.0 - 2.0 * intrinsics(0, 2) / width;
165  custom_proj[2][1] = -1.0 + 2.0 * intrinsics(1, 2) / height;
166  custom_proj[2][2] = (-far - near) / (far - near);
167  custom_proj[2][3] = -1.0;
168 
169  custom_proj[3][0] = 0.0;
170  custom_proj[3][1] = 0.0;
171  custom_proj[3][2] = -2.0 * far * near / (far - near);
172  custom_proj[3][3] = 0.0;
173 
174  camera_->setCustomProjection(custom_proj, near, far);
175 
176  projection_.is_intrinsic = true;
177  projection_.is_ortho = false;
178  projection_.proj.intrinsics.fx = intrinsics(0, 0);
179  projection_.proj.intrinsics.fy = intrinsics(1, 1);
180  projection_.proj.intrinsics.cx = intrinsics(0, 2);
181  projection_.proj.intrinsics.cy = intrinsics(1, 2);
182  projection_.proj.intrinsics.near_plane = near;
183  projection_.proj.intrinsics.far_plane = far;
184  projection_.proj.intrinsics.width = width;
185  projection_.proj.intrinsics.height = height;
186 }
187 
188 double FilamentCamera::GetNear() const { return camera_->getNear(); }
189 
190 double FilamentCamera::GetFar() const { return camera_->getCullingFar(); }
191 
193  if (projection_.is_ortho) {
194  // technically orthographic projection is lim(fov->0) as dist->inf,
195  // but it also serves as an obviously wrong value if you call
196  // GetFieldOfView() after setting an orthographic projection
197  return 0.0;
198  } else if (projection_.is_intrinsic) {
199  double fov_rad =
200  2.0 * std::atan(0.5 * projection_.proj.intrinsics.height /
201  projection_.proj.intrinsics.fy);
202  return 180.0 / 3.141592 * fov_rad;
203  } else {
204  return projection_.proj.perspective.fov;
205  }
206 }
207 
209  if (projection_.is_ortho) {
211  } else if (projection_.is_intrinsic) {
213  } else {
214  return projection_.proj.perspective.fov_type;
215  }
216 }
217 
218 void FilamentCamera::LookAt(const Eigen::Vector3f& center,
219  const Eigen::Vector3f& eye,
220  const Eigen::Vector3f& up) {
221  // We set the camera's model matrix instead of using lookAt, which sets
222  // the view matrix, because we cannot set the view matrix directly, which
223  // the rotation interactors need to do.
224  using namespace filament::math;
225  auto m = mat4f::lookAt(float3(eye.x(), eye.y(), eye.z()),
226  float3(center.x(), center.y(), center.z()),
227  float3(up.x(), up.y(), up.z()));
228 
229  camera_->setModelMatrix(m);
230 }
231 
232 Eigen::Vector3f FilamentCamera::GetPosition() const {
233  auto cam_pos = camera_->getPosition();
234  return {cam_pos.x, cam_pos.y, cam_pos.z};
235 }
236 
237 Eigen::Vector3f FilamentCamera::GetForwardVector() const {
238  auto forward = camera_->getForwardVector();
239  return {forward.x, forward.y, forward.z};
240 }
241 
242 Eigen::Vector3f FilamentCamera::GetLeftVector() const {
243  auto left = camera_->getLeftVector();
244  return {left.x, left.y, left.z};
245 }
246 
247 Eigen::Vector3f FilamentCamera::GetUpVector() const {
248  auto up = camera_->getUpVector();
249  return {up.x, up.y, up.z};
250 }
251 
253  auto ftransform = camera_->getModelMatrix();
254  return FilamentToCameraTransform(ftransform);
255 }
256 
258  auto ftransform = camera_->getViewMatrix(); // returns mat4 (not mat4f)
259  return FilamentToCameraTransform(ftransform);
260 }
261 
263  auto ft = camera_->getProjectionMatrix(); // mat4 (not mat4f)
264  Camera::ProjectionMatrix::MatrixType proj;
265  proj << float(ft(0, 0)), float(ft(0, 1)), float(ft(0, 2)), float(ft(0, 3)),
266  float(ft(1, 0)), float(ft(1, 1)), float(ft(1, 2)), float(ft(1, 3)),
267  float(ft(2, 0)), float(ft(2, 1)), float(ft(2, 2)), float(ft(2, 3)),
268  float(ft(3, 0)), float(ft(3, 1)), float(ft(3, 2)), float(ft(3, 3));
269  return Camera::ProjectionMatrix(proj);
270 }
271 
273  auto ftransform =
274  camera_->getCullingProjectionMatrix(); // mat4 (not mat4f)
275  return FilamentToCameraTransform(ftransform);
276 }
277 
278 Eigen::Vector2f FilamentCamera::GetNDC(const Eigen::Vector3f& pt) const {
279  auto vtransform = camera_->getViewMatrix();
280  auto ptransform = camera_->getProjectionMatrix();
281  filament::math::float4 p(pt(0), pt(1), pt(2), 1.f);
282  auto clip_space_p = ptransform * vtransform * p;
283  filament::math::float2 ndc_space_p;
284  ndc_space_p.x = float(clip_space_p.x / clip_space_p.w);
285  ndc_space_p.y = float(clip_space_p.y / clip_space_p.w);
286 
287  return {ndc_space_p.x, ndc_space_p.y};
288 }
289 
290 double FilamentCamera::GetViewZ(float z_buffer) const {
291  double z_near = GetNear();
292  if (z_buffer >= 1.0f) {
294  } else {
295  return -z_near / (1.0 - z_buffer);
296  }
297 }
298 
300  return projection_;
301 }
302 
303 void FilamentCamera::SetModelMatrix(const Eigen::Vector3f& forward,
304  const Eigen::Vector3f& left,
305  const Eigen::Vector3f& up) {
306  using namespace filament;
307 
308  math::mat4f ftransform = camera_->getModelMatrix();
309  ftransform[0].xyz = math::float3(left.x(), left.y(), left.z());
310  ftransform[1].xyz = math::float3(up.x(), up.y(), up.z());
311  ftransform[2].xyz = math::float3(forward.x(), forward.y(), forward.z());
312 
313  camera_->setModelMatrix(ftransform); // model matrix uses mat4f
314 }
315 
317  auto ftransform = CameraToFilamentTransformF(view);
318  camera_->setModelMatrix(ftransform); // model matrix uses mat4f
319 }
320 
322  float x, float y, float z, float view_width, float view_height) const {
323  Eigen::Vector4f gl_pt(2.0f * x / view_width - 1.0f,
324  2.0f * y / view_height - 1.0f, 2.0f * z - 1.0f, 1.0f);
325 
326  auto proj = GetProjectionMatrix();
327  Eigen::Vector4f obj_pt = (proj * GetViewMatrix()).inverse() * gl_pt;
328  return {obj_pt.x() / obj_pt.w(), obj_pt.y() / obj_pt.w(),
329  obj_pt.z() / obj_pt.w()};
330 }
331 
332 } // namespace rendering
333 } // namespace visualization
334 } // namespace cloudViewer
int width
int height
virtual const ProjectionInfo & GetProjection() const =0
Eigen::Transform< float, 3, Eigen::Affine > Transform
Definition: Camera.h:29
virtual Transform GetModelMatrix() const =0
Eigen::Transform< float, 3, Eigen::Projective > ProjectionMatrix
Definition: Camera.h:30
ProjectionMatrix GetProjectionMatrix() const override
const ProjectionInfo & GetProjection() const override
FovType GetFieldOfViewType() const override
only valid if fov was passed to SetProjection()
void LookAt(const Eigen::Vector3f &center, const Eigen::Vector3f &eye, const Eigen::Vector3f &up) override
Eigen::Vector3f Unproject(float x, float y, float z, float view_width, float view_height) const override
void SetModelMatrix(const Transform &view) override
void SetProjection(double fov, double aspect, double near, double far, FovType fov_type) override
double GetViewZ(float z_buffer) const override
Eigen::Vector2f GetNDC(const Eigen::Vector3f &pt) const override
double GetFieldOfView() const override
only valid if fov was passed to SetProjection()
void CopyFrom(const Camera *camera) override
__device__ __forceinline__ float infinity()
Definition: result_set.h:36
Generic file read and write utility for python interface.
struct cloudViewer::visualization::rendering::Camera::ProjectionInfo::@23::@26 intrinsics
struct cloudViewer::visualization::rendering::Camera::ProjectionInfo::@23::@24 ortho
union cloudViewer::visualization::rendering::Camera::ProjectionInfo::@23 proj
struct cloudViewer::visualization::rendering::Camera::ProjectionInfo::@23::@25 perspective