ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
VisualizerRender.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 
8 // clang-format off
9 #include "visualization/visualizer/Visualizer.h" // must include first
10 // clang-format on
11 #include <IJsonConvertibleIO.h>
12 #include <ImageIO.h>
13 #include <Logging.h>
14 #include <ecvMesh.h>
15 #include <ecvPointCloud.h>
16 
18 #include "io/PointCloudIO.h"
22 
23 #if defined(BUILD_GUI)
24 namespace bluegl {
25 int bind();
26 void unbind();
27 } // namespace bluegl
28 #endif
29 
30 namespace cloudViewer {
31 namespace visualization {
32 using namespace cloudViewer;
33 
35 #if defined(BUILD_GUI)
36  // With the current link strategy the OpenGL functions are bound to
37  // Filament's BlueGL internal stubs which are initially null. BlueGL loads
38  // the 'real' OpenGL functions dynamically. In new visualizer, Filament
39  // automatically initializes BlueGL for us, but here we have to do manually
40  // otherwise the OpenGL functions will point to null functions and crash.
41  if (bluegl::bind()) {
42  utility::LogWarning("Visualizer::InitOpenGL: bluegl::bind() error.");
43  }
44 #endif
45 
46  glewExperimental = true;
47  const GLenum init_ret = glewInit();
48 
49  // In headless mode (GLFW_PLATFORM_NULL), GLEW may return
50  // GLEW_ERROR_NO_GL_VERSION, which should be allowed.
51  // This is similar to how GLEW_ERROR_NO_GLX_DISPLAY is handled.
52  // Use glfwGetPlatform() to detect headless mode since GLFW is already
53  // initialized at this point (InitOpenGL() is called after
54  // CreateVisualizerWindow()).
55  bool is_headless = (glfwGetPlatform() == GLFW_PLATFORM_NULL);
56 
57  if (init_ret != GLEW_OK && init_ret != GLEW_ERROR_NO_GLX_DISPLAY) {
58  // Allow GLEW_ERROR_NO_GL_VERSION in headless mode
59  if (is_headless && init_ret == GLEW_ERROR_NO_GL_VERSION) {
61  "GLEW initialization returned GLEW_ERROR_NO_GL_VERSION in "
62  "headless mode, continuing anyway.");
63  } else {
64  const std::string err_msg{reinterpret_cast<const char *>(
65  glewGetErrorString(init_ret))};
66  utility::LogWarning("Failed to initialize GLEW: {} ({})", err_msg,
67  init_ret);
68  return false;
69  }
70  }
71 
72  render_fbo_ = 0;
73 
74  glGenVertexArrays(1, &vao_id_);
75  glBindVertexArray(vao_id_);
76 
77  // depth test
78  glEnable(GL_DEPTH_TEST);
79  glClearDepth(1.0f);
80 
81  // pixel alignment
82  glPixelStorei(GL_PACK_ALIGNMENT, 1);
83  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
84 
85  // polygon rendering
86  glEnable(GL_CULL_FACE);
87 
88  // glReadPixels always read front buffer
89  glReadBuffer(GL_FRONT);
90 
91  return true;
92 }
93 
94 void Visualizer::Render(bool render_screen) {
95  glfwMakeContextCurrent(window_);
96 
97  view_control_ptr_->SetViewMatrices();
98 
99  if (render_screen) {
100  if (render_fbo_ != 0) {
101  utility::LogWarning("Render framebuffer is not released.");
102  }
103 
104  glGenFramebuffers(1, &render_fbo_);
105  glBindFramebuffer(GL_FRAMEBUFFER, render_fbo_);
106 
107  int tex_w = view_control_ptr_->GetWindowWidth();
108  int tex_h = view_control_ptr_->GetWindowHeight();
109 
110  glGenTextures(1, &render_rgb_tex_);
111  glBindTexture(GL_TEXTURE_2D, render_rgb_tex_);
112  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB,
113  GL_FLOAT, NULL);
114  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
115  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
116  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
117  GL_TEXTURE_2D, render_rgb_tex_, 0);
118 
119  glGenRenderbuffers(1, &render_depth_stencil_rbo_);
120  glBindRenderbuffer(GL_RENDERBUFFER, render_depth_stencil_rbo_);
121  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_w,
122  tex_h);
123  glBindRenderbuffer(GL_RENDERBUFFER, 0);
124  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
125  GL_RENDERBUFFER, render_depth_stencil_rbo_);
126  }
127 
128  glEnable(GL_MULTISAMPLE);
129  glDisable(GL_BLEND);
130  auto &background_color = render_option_ptr_->background_color_;
131  glClearColor((GLclampf)background_color(0), (GLclampf)background_color(1),
132  (GLclampf)background_color(2), 1.0f);
133  glClearDepth(1.0f);
134  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135 
136  for (const auto &renderer_ptr : geometry_renderer_ptrs_) {
137  renderer_ptr->Render(*render_option_ptr_, *view_control_ptr_);
138  }
139  for (const auto &renderer_ptr : utility_renderer_ptrs_) {
140  RenderOption *opt = render_option_ptr_.get();
141  auto optIt = utility_renderer_opts_.find(renderer_ptr);
142  if (optIt != utility_renderer_opts_.end()) {
143  opt = &optIt->second;
144  }
145  renderer_ptr->Render(*opt, *view_control_ptr_);
146  }
147 
148  glfwSwapBuffers(window_);
149 }
150 
151 void Visualizer::ResetViewPoint(bool reset_bounding_box /* = false*/) {
152  if (reset_bounding_box) {
153  view_control_ptr_->ResetBoundingBox();
154  for (const auto &geometry_ptr : geometry_ptrs_) {
155  view_control_ptr_->FitInGeometry(*(geometry_ptr));
156  }
158  const auto &boundingbox = view_control_ptr_->GetBoundingBox();
160  boundingbox.GetMaxExtent() * 0.2,
161  boundingbox.GetMinBound());
162  coordinate_frame_mesh_renderer_ptr_->UpdateGeometry();
163  }
164  }
165  view_control_ptr_->Reset();
166  is_redraw_required_ = true;
167 }
168 
170  ViewParameters current_status;
171  if (view_control_ptr_->ConvertToViewParameters(current_status) == false) {
172  utility::LogWarning("Something is wrong copying view status.");
173  }
174  ViewTrajectory trajectory;
175  trajectory.view_status_.push_back(current_status);
176  std::string clipboard_string;
177  if (io::WriteIJsonConvertibleToJSONString(clipboard_string, trajectory) ==
178  false) {
179  utility::LogWarning("Something is wrong copying view status.");
180  }
181  glfwSetClipboardString(window_, clipboard_string.c_str());
182 }
183 
185  const char *clipboard_string_buffer = glfwGetClipboardString(window_);
186  if (clipboard_string_buffer != NULL) {
187  std::string clipboard_string(clipboard_string_buffer);
188  ViewTrajectory trajectory;
189  if (io::ReadIJsonConvertibleFromJSONString(clipboard_string,
190  trajectory) == false) {
191  utility::LogWarning("Something is wrong copying view status.");
192  }
193  if (trajectory.view_status_.size() != 1) {
194  utility::LogWarning("Something is wrong copying view status.");
195  }
196  view_control_ptr_->ConvertFromViewParameters(
197  trajectory.view_status_[0]);
198  }
199 }
200 
201 std::shared_ptr<geometry::Image> Visualizer::CaptureScreenFloatBuffer(
202  bool do_render /* = true*/) {
203  geometry::Image screen_image;
204  screen_image.Prepare(view_control_ptr_->GetWindowWidth(),
205  view_control_ptr_->GetWindowHeight(), 3, 4);
206  if (do_render) {
207  Render(true);
208  is_redraw_required_ = false;
209  } else {
210  glfwMakeContextCurrent(window_);
211  }
212  glFinish();
213  glReadPixels(0, 0, view_control_ptr_->GetWindowWidth(),
214  view_control_ptr_->GetWindowHeight(), GL_RGB, GL_FLOAT,
215  screen_image.data_.data());
216 
217  // glReadPixels get the screen in a vertically flipped manner
218  // Thus we should flip it back.
219  auto image_ptr = std::make_shared<geometry::Image>();
220  image_ptr->Prepare(view_control_ptr_->GetWindowWidth(),
221  view_control_ptr_->GetWindowHeight(), 3, 4);
222  int bytes_per_line = screen_image.BytesPerLine();
223  for (int i = 0; i < screen_image.height_; i++) {
224  memcpy(image_ptr->data_.data() + bytes_per_line * i,
225  screen_image.data_.data() +
226  bytes_per_line * (screen_image.height_ - i - 1),
227  bytes_per_line);
228  }
229  return image_ptr;
230 }
231 
232 void Visualizer::CaptureScreenImage(const std::string &filename /* = ""*/,
233  bool do_render /* = true*/) {
234  std::string png_filename = filename;
235  std::string camera_filename;
236  if (png_filename.empty()) {
237  std::string timestamp = utility::GetCurrentTimeStamp();
238  png_filename = "ScreenCapture_" + timestamp + ".png";
239  camera_filename = "ScreenCamera_" + timestamp + ".json";
240  }
241  geometry::Image screen_image;
242  screen_image.Prepare(view_control_ptr_->GetWindowWidth(),
243  view_control_ptr_->GetWindowHeight(), 3, 1);
244  if (do_render) {
245  Render();
246  is_redraw_required_ = false;
247  }
248  glFinish();
249  glReadPixels(0, 0, view_control_ptr_->GetWindowWidth(),
250  view_control_ptr_->GetWindowHeight(), GL_RGB, GL_UNSIGNED_BYTE,
251  screen_image.data_.data());
252 
253  // glReadPixels get the screen in a vertically flipped manner
254  // Thus we should flip it back.
255  geometry::Image png_image;
256  png_image.Prepare(view_control_ptr_->GetWindowWidth(),
257  view_control_ptr_->GetWindowHeight(), 3, 1);
258  int bytes_per_line = screen_image.BytesPerLine();
259  for (int i = 0; i < screen_image.height_; i++) {
260  memcpy(png_image.data_.data() + bytes_per_line * i,
261  screen_image.data_.data() +
262  bytes_per_line * (screen_image.height_ - i - 1),
263  bytes_per_line);
264  }
265 
266  utility::LogDebug("[Visualizer] Screen capture to {}",
267  png_filename.c_str());
268  io::WriteImage(png_filename, png_image);
269  if (!camera_filename.empty()) {
270  utility::LogDebug("[Visualizer] Screen camera capture to {}",
271  camera_filename.c_str());
273  view_control_ptr_->ConvertToPinholeCameraParameters(parameter);
274  io::WriteIJsonConvertible(camera_filename, parameter);
275  }
276 }
277 
278 std::shared_ptr<geometry::Image> Visualizer::CaptureDepthFloatBuffer(
279  bool do_render /* = true*/) {
280  geometry::Image depth_image;
281  depth_image.Prepare(view_control_ptr_->GetWindowWidth(),
282  view_control_ptr_->GetWindowHeight(), 1, 4);
283  if (do_render) {
284  Render();
285  is_redraw_required_ = false;
286  }
287  glFinish();
288 
289 #if __APPLE__
290  // On OSX with Retina display and glfw3, there is a bug with glReadPixels().
291  // When using glReadPixels() to read a block of depth data. The data is
292  // horizontally stretched (vertically it is fine). This issue is related
293  // to GLFW_SAMPLES hint. When it is set to 0 (anti-aliasing disabled),
294  // glReadPixels() works fine. See this post for details:
295  // http://stackoverflow.com/questions/30608121/glreadpixel-one-pass-vs-looping-through-points
296  // The reason of this bug is unknown. The current workaround is to read
297  // depth buffer column by column. This is 15~30 times slower than one block
298  // reading glReadPixels().
299  std::vector<float> float_buffer(depth_image.height_);
300  float *p = (float *)depth_image.data_.data();
301  for (int j = 0; j < depth_image.width_; j++) {
302  glReadPixels(j, 0, 1, depth_image.height_, GL_DEPTH_COMPONENT, GL_FLOAT,
303  float_buffer.data());
304  for (int i = 0; i < depth_image.height_; i++) {
305  p[i * depth_image.width_ + j] = float_buffer[i];
306  }
307  }
308 #else //__APPLE__
309  // By default, glReadPixels read a block of depth buffer.
310  glReadPixels(0, 0, depth_image.width_, depth_image.height_,
311  GL_DEPTH_COMPONENT, GL_FLOAT, depth_image.data_.data());
312 #endif //__APPLE__
313 
314  // glReadPixels get the screen in a vertically flipped manner
315  // We should flip it back, and convert it to the correct depth value
316  auto image_ptr = std::make_shared<geometry::Image>();
317  double z_near = view_control_ptr_->GetZNear();
318  double z_far = view_control_ptr_->GetZFar();
319 
320  image_ptr->Prepare(view_control_ptr_->GetWindowWidth(),
321  view_control_ptr_->GetWindowHeight(), 1, 4);
322  for (int i = 0; i < depth_image.height_; i++) {
323  float *p_depth = (float *)(depth_image.data_.data() +
324  depth_image.BytesPerLine() *
325  (depth_image.height_ - i - 1));
326  float *p_image = (float *)(image_ptr->data_.data() +
327  image_ptr->BytesPerLine() * i);
328  for (int j = 0; j < depth_image.width_; j++) {
329  if (p_depth[j] == 1.0) {
330  continue;
331  }
332  double z_depth =
333  2.0 * z_near * z_far /
334  (z_far + z_near -
335  (2.0 * (double)p_depth[j] - 1.0) * (z_far - z_near));
336  p_image[j] = (float)z_depth;
337  }
338  }
339  return image_ptr;
340 }
341 
342 void Visualizer::CaptureDepthImage(const std::string &filename /* = ""*/,
343  bool do_render /* = true*/,
344  double depth_scale /* = 1000.0*/) {
345  std::string png_filename = filename;
346  std::string camera_filename;
347  if (png_filename.empty()) {
348  std::string timestamp = utility::GetCurrentTimeStamp();
349  png_filename = "DepthCapture_" + timestamp + ".png";
350  camera_filename = "DepthCamera_" + timestamp + ".json";
351  }
352  geometry::Image depth_image;
353  depth_image.Prepare(view_control_ptr_->GetWindowWidth(),
354  view_control_ptr_->GetWindowHeight(), 1, 4);
355 
356  if (do_render) {
357  Render();
358  is_redraw_required_ = false;
359  }
360  glFinish();
361 
362 #if __APPLE__
363  // On OSX with Retina display and glfw3, there is a bug with glReadPixels().
364  // When using glReadPixels() to read a block of depth data. The data is
365  // horizontally streched (vertically it is fine). This issue is related
366  // to GLFW_SAMPLES hint. When it is set to 0 (anti-aliasing disabled),
367  // glReadPixels() works fine. See this post for details:
368  // http://stackoverflow.com/questions/30608121/glreadpixel-one-pass-vs-looping-through-points
369  // The reason of this bug is unknown. The current workaround is to read
370  // depth buffer column by column. This is 15~30 times slower than one block
371  // reading glReadPixels().
372  std::vector<float> float_buffer(depth_image.height_);
373  float *p = (float *)depth_image.data_.data();
374  for (int j = 0; j < depth_image.width_; j++) {
375  glReadPixels(j, 0, 1, depth_image.width_, GL_DEPTH_COMPONENT, GL_FLOAT,
376  float_buffer.data());
377  for (int i = 0; i < depth_image.height_; i++) {
378  p[i * depth_image.width_ + j] = float_buffer[i];
379  }
380  }
381 #else //__APPLE__
382  // By default, glReadPixels read a block of depth buffer.
383  glReadPixels(0, 0, depth_image.width_, depth_image.height_,
384  GL_DEPTH_COMPONENT, GL_FLOAT, depth_image.data_.data());
385 #endif //__APPLE__
386 
387  // glReadPixels get the screen in a vertically flipped manner
388  // We should flip it back, and convert it to the correct depth value
389  geometry::Image png_image;
390  double z_near = view_control_ptr_->GetZNear();
391  double z_far = view_control_ptr_->GetZFar();
392 
393  png_image.Prepare(view_control_ptr_->GetWindowWidth(),
394  view_control_ptr_->GetWindowHeight(), 1, 2);
395  for (int i = 0; i < depth_image.height_; i++) {
396  float *p_depth = (float *)(depth_image.data_.data() +
397  depth_image.BytesPerLine() *
398  (depth_image.height_ - i - 1));
399  uint16_t *p_png = (uint16_t *)(png_image.data_.data() +
400  png_image.BytesPerLine() * i);
401  for (int j = 0; j < depth_image.width_; j++) {
402  if (p_depth[j] == 1.0) {
403  continue;
404  }
405  double z_depth =
406  2.0 * z_near * z_far /
407  (z_far + z_near -
408  (2.0 * (double)p_depth[j] - 1.0) * (z_far - z_near));
409  p_png[j] = (uint16_t)std::min(std::round(depth_scale * z_depth),
410  (double)INT16_MAX);
411  }
412  }
413 
414  utility::LogDebug("[Visualizer] Depth capture to {}", png_filename.c_str());
415  io::WriteImage(png_filename, png_image);
416  if (!camera_filename.empty()) {
417  utility::LogDebug("[Visualizer] Depth camera capture to {}",
418  camera_filename.c_str());
420  view_control_ptr_->ConvertToPinholeCameraParameters(parameter);
421  io::WriteIJsonConvertible(camera_filename, parameter);
422  }
423 }
424 
426  const std::string &filename /* = ""*/,
427  bool do_render /* = true*/,
428  bool convert_to_world_coordinate /* = false*/) {
429  std::string ply_filename = filename;
430  std::string camera_filename;
431  if (ply_filename.empty()) {
432  std::string timestamp = utility::GetCurrentTimeStamp();
433  ply_filename = "DepthCapture_" + timestamp + ".ply";
434  camera_filename = "DepthCamera_" + timestamp + ".json";
435  }
436  geometry::Image depth_image;
437  depth_image.Prepare(view_control_ptr_->GetWindowWidth(),
438  view_control_ptr_->GetWindowHeight(), 1, 4);
439 
440  if (do_render) {
441  Render();
442  is_redraw_required_ = false;
443  }
444  glFinish();
445 
446 #if __APPLE__
447  // On OSX with Retina display and glfw3, there is a bug with glReadPixels().
448  // When using glReadPixels() to read a block of depth data. The data is
449  // horizontally stretched (vertically it is fine). This issue is related
450  // to GLFW_SAMPLES hint. When it is set to 0 (anti-aliasing disabled),
451  // glReadPixels() works fine. See this post for details:
452  // http://stackoverflow.com/questions/30608121/glreadpixel-one-pass-vs-looping-through-points
453  // The reason of this bug is unknown. The current workaround is to read
454  // depth buffer column by column. This is 15~30 times slower than one block
455  // reading glReadPixels().
456  std::vector<float> float_buffer(depth_image.height_);
457  float *p = (float *)depth_image.data_.data();
458  for (int j = 0; j < depth_image.width_; j++) {
459  glReadPixels(j, 0, 1, depth_image.width_, GL_DEPTH_COMPONENT, GL_FLOAT,
460  float_buffer.data());
461  for (int i = 0; i < depth_image.height_; i++) {
462  p[i * depth_image.width_ + j] = float_buffer[i];
463  }
464  }
465 #else //__APPLE__
466  // By default, glReadPixels read a block of depth buffer.
467  glReadPixels(0, 0, depth_image.width_, depth_image.height_,
468  GL_DEPTH_COMPONENT, GL_FLOAT, depth_image.data_.data());
469 #endif //__APPLE__
470 
471  gl_util::GLMatrix4f mvp_matrix;
472  if (convert_to_world_coordinate) {
473  mvp_matrix = view_control_ptr_->GetMVPMatrix();
474  } else {
475  mvp_matrix = view_control_ptr_->GetProjectionMatrix();
476  }
477 
478  // glReadPixels get the screen in a vertically flipped manner
479  // We should flip it back, and convert it to the correct depth value
480  ccPointCloud depth_pointcloud;
481  for (int i = 0; i < depth_image.height_; i++) {
482  float *p_depth = (float *)(depth_image.data_.data() +
483  depth_image.BytesPerLine() * i);
484  for (int j = 0; j < depth_image.width_; j++) {
485  if (p_depth[j] == 1.0) {
486  continue;
487  }
488  depth_pointcloud.addPoint(gl_util::Unproject(
489  Eigen::Vector3d(j + 0.5, i + 0.5, p_depth[j]), mvp_matrix,
490  view_control_ptr_->GetWindowWidth(),
491  view_control_ptr_->GetWindowHeight()));
492  }
493  }
494 
495  utility::LogDebug("[Visualizer] Depth point cloud capture to {}",
496  ply_filename.c_str());
497  io::WritePointCloud(ply_filename, depth_pointcloud, {});
498  if (!camera_filename.empty()) {
499  utility::LogDebug("[Visualizer] Depth camera capture to {}",
500  camera_filename.c_str());
502  view_control_ptr_->ConvertToPinholeCameraParameters(parameter);
503  io::WriteIJsonConvertible(camera_filename, parameter);
504  }
505 }
506 
507 void Visualizer::CaptureRenderOption(const std::string &filename /* = ""*/) {
508  std::string json_filename = filename;
509  if (json_filename.empty()) {
510  std::string timestamp = utility::GetCurrentTimeStamp();
511  json_filename = "RenderOption_" + timestamp + ".json";
512  }
513  utility::LogDebug("[Visualizer] Render option capture to {}",
514  json_filename.c_str());
516 }
517 
518 } // namespace visualization
519 } // namespace cloudViewer
std::string filename
#define NULL
static std::shared_ptr< ccMesh > CreateCoordinateFrame(double size=1.0, const Eigen::Vector3d &origin=Eigen::Vector3d(0.0, 0.0, 0.0))
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
Contains both intrinsic and extrinsic pinhole camera parameters.
The Image class stores image with customizable width, height, num of channels and bytes per channel.
Definition: Image.h:33
Image & Prepare(int width, int height, int num_of_channels, int bytes_per_channel)
Prepare Image properties and allocate Image buffer.
Definition: Image.h:109
int height_
Height of the image.
Definition: Image.h:221
int BytesPerLine() const
Returns data size per line (row, or the width) in bytes.
Definition: Image.h:122
int width_
Width of the image.
Definition: Image.h:219
std::vector< uint8_t > data_
Image storage buffer.
Definition: Image.h:227
Defines rendering options for visualizer.
Definition: RenderOption.h:20
std::vector< ViewParameters > view_status_
std::vector< std::shared_ptr< glsl::GeometryRenderer > > utility_renderer_ptrs_
Definition: Visualizer.h:297
std::shared_ptr< geometry::Image > CaptureDepthFloatBuffer(bool do_render=true)
void CaptureDepthPointCloud(const std::string &filename="", bool do_render=true, bool convert_to_world_coordinate=false)
Function to capture and save local point cloud.
virtual bool InitOpenGL()
Function to initialize OpenGL.
std::shared_ptr< ccMesh > coordinate_frame_mesh_ptr_
Definition: Visualizer.h:304
void CaptureScreenImage(const std::string &filename="", bool do_render=true)
Function to capture and save a screen image.
std::unordered_set< std::shared_ptr< const ccHObject > > geometry_ptrs_
Definition: Visualizer.h:287
std::unordered_map< std::shared_ptr< glsl::GeometryRenderer >, RenderOption > utility_renderer_opts_
Definition: Visualizer.h:301
std::unique_ptr< RenderOption > render_option_ptr_
Definition: Visualizer.h:284
void ResetViewPoint(bool reset_bounding_box=false)
Function to reset view point.
std::unordered_set< std::shared_ptr< glsl::GeometryRenderer > > geometry_renderer_ptrs_
Definition: Visualizer.h:291
std::shared_ptr< geometry::Image > CaptureScreenFloatBuffer(bool do_render=true)
Function to capture screen and store RGB in a float buffer.
virtual void Render(bool render_screen=false)
std::unique_ptr< ViewControl > view_control_ptr_
Definition: Visualizer.h:281
void CaptureRenderOption(const std::string &filename="")
void CaptureDepthImage(const std::string &filename="", bool do_render=true, double depth_scale=1000.0)
std::shared_ptr< glsl::CoordinateFrameRenderer > coordinate_frame_mesh_renderer_ptr_
Definition: Visualizer.h:306
#define LogWarning(...)
Definition: Logging.h:72
#define LogDebug(...)
Definition: Logging.h:90
int min(int a, int b)
Definition: cutil_math.h:53
bool ReadIJsonConvertibleFromJSONString(const std::string &json_string, cloudViewer::utility::IJsonConvertible &object)
bool WriteIJsonConvertible(const std::string &filename, const cloudViewer::utility::IJsonConvertible &object)
bool WriteIJsonConvertibleToJSONString(std::string &json_string, const cloudViewer::utility::IJsonConvertible &object)
bool WriteImage(const std::string &filename, const geometry::Image &image, int quality=kCloudViewerImageIODefaultQuality)
bool WritePointCloud(const std::string &filename, const ccPointCloud &pointcloud, const WritePointCloudOption &params)
std::string GetCurrentTimeStamp()
Returns current time stamp.
Definition: Helper.cpp:286
Eigen::Matrix< float, 4, 4, Eigen::ColMajor > GLMatrix4f
Definition: GLHelper.h:35
Eigen::Vector3d Unproject(const Eigen::Vector3d &screen_point, const GLMatrix4f &mvp_matrix, const int width, const int height)
Definition: GLHelper.cpp:97
Generic file read and write utility for python interface.