ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FilamentRenderToBuffer.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 // 4146: PixelBufferDescriptor assert unsigned is positive before subtracting
12 // but MSVC can't figure that out.
13 // 4293: Filament's utils/algorithm.h utils::details::clz() does strange
14 // things with MSVC. Somehow sizeof(unsigned int) > 4, but its size is
15 // 32 so that x >> 32 gives a warning. (Or maybe the compiler can't
16 // determine the if statement does not run.)
17 #ifdef _MSC_VER
18 #pragma warning(push)
19 #pragma warning(disable : 4068 4146 4293)
20 #endif // _MSC_VER
21 
22 #include <filament/Engine.h>
23 #include <filament/RenderableManager.h>
24 #include <filament/Renderer.h>
25 #include <filament/Scene.h>
26 #include <filament/SwapChain.h>
27 #include <filament/Texture.h>
28 #include <filament/View.h>
29 #include <filament/Viewport.h>
30 
31 #ifdef _MSC_VER
32 #pragma warning(pop)
33 #endif // _MSC_VER
34 
35 #include <Logging.h>
36 
41 
42 namespace cloudViewer {
43 namespace visualization {
44 namespace rendering {
45 
47  : engine_(engine) {
48  renderer_ = engine_.createRenderer();
49 }
50 
52  if (view_) delete view_;
53 
54  engine_.destroy(swapchain_);
55  engine_.destroy(renderer_);
56 
57  if (buffer_) {
58  free(buffer_);
59  buffer_ = nullptr;
60 
61  buffer_size_ = 0;
62  }
63 }
64 
66  Scene* scene,
67  int width,
68  int height,
69  int n_channels,
70  bool depth_image,
72  if (!scene) {
74  "No Scene object was provided for rendering into buffer");
75  cb({0, 0, 0, nullptr, 0});
76  return;
77  }
78 
79  if (pending_) {
81  "Render to buffer can process only one request at time");
82  cb({0, 0, 0, nullptr, 0});
83  return;
84  }
85 
86  if (!depth_image && (n_channels != 3 && n_channels != 4)) {
88  "Render to buffer must have either 3 or 4 channels");
89  cb({0, 0, 0, nullptr, 0});
90  return;
91  }
92 
93  if (depth_image) {
94  n_channels_ = 1;
95  } else {
96  n_channels_ = n_channels;
97  }
98  depth_image_ = depth_image;
99  pending_ = true;
100  callback_ = cb;
101 
102  // Create a proper copy of the View with scen attached
103  CopySettings(view);
104  auto* downcast_scene = static_cast<FilamentScene*>(scene);
105  if (downcast_scene) {
106  view_->SetScene(*downcast_scene);
107  scene_ = downcast_scene;
108  }
110 }
111 
113  const std::uint32_t height) {
114  if (swapchain_) {
115  engine_.destroy(swapchain_);
116  }
117 
118  swapchain_ = engine_.createSwapChain(width, height,
119  filament::SwapChain::CONFIG_READABLE);
120  view_->SetViewport(0, 0, width, height);
121 
122  width_ = width;
123  height_ = height;
124 
125  if (depth_image_) {
126  buffer_size_ = width * height * sizeof(std::float_t);
127  } else {
128  buffer_size_ = width * height * n_channels_ * sizeof(std::uint8_t);
129  }
130  if (buffer_) {
131  buffer_ = static_cast<std::uint8_t*>(realloc(buffer_, buffer_size_));
132  } else {
133  buffer_ = static_cast<std::uint8_t*>(malloc(buffer_size_));
134  }
135 }
136 
137 void FilamentRenderToBuffer::CopySettings(const View* view) {
138  view_ = new FilamentView(engine_, EngineInstance::GetResourceManager());
139  auto* downcast = static_cast<const FilamentView*>(view);
140  if (downcast) {
141  view_->CopySettingsFrom(*downcast);
142  }
143  if (depth_image_) {
144  // Disable post-processing when rendering to depth image. It's uncessary
145  // overhead and the depth buffer is discarded when post-processing is
146  // enabled so the returned image is all 0s.
147  view_->ConfigureForColorPicking();
148  // Set shadowing to true as there is a pixel coordinate scaling
149  // issue on Apple Retina displays that results in quarter size depth
150  // images if shadowing is disabled.
151  view_->SetShadowing(true, View::ShadowType::kPCF);
152  }
153 }
154 
156 
157 using PBDParams = std::tuple<FilamentRenderToBuffer*,
159 
160 void FilamentRenderToBuffer::ReadPixelsCallback(void*, size_t, void* user) {
161  auto params = static_cast<PBDParams*>(user);
164  std::tie(self, callback) = *params;
165 
166  callback({self->width_, self->height_, self->n_channels_, self->buffer_,
167  self->buffer_size_});
168 
169  // Unassign the callback, in case it captured ourself. Then we would never
170  // get freed.
171  self->callback_ = nullptr;
172 
173  self->frame_done_ = true;
174  delete params;
175 }
176 
178  frame_done_ = false;
179  scene_->HideRefractedMaterials();
180  if (renderer_->beginFrame(swapchain_)) {
181  renderer_->render(view_->GetNativeView());
182 
183  using namespace filament;
184  using namespace backend;
185 
186  auto format = (n_channels_ == 3 ? PixelDataFormat::RGB
187  : PixelDataFormat::RGBA);
188  auto type = PixelDataType::UBYTE;
189  if (depth_image_) {
190  format = PixelDataFormat::DEPTH_COMPONENT;
191  type = PixelDataType::FLOAT;
192  }
193  auto user_param = new PBDParams(this, callback_);
194  PixelBufferDescriptor pd(buffer_, buffer_size_, format, type,
195  ReadPixelsCallback, user_param);
196  auto vp = view_->GetNativeView()->getViewport();
197 
198  renderer_->readPixels(vp.left, vp.bottom, vp.width, vp.height,
199  std::move(pd));
200 
201  renderer_->endFrame();
202  }
203  scene_->HideRefractedMaterials(false);
204 
205  pending_ = false;
206 }
207 
209  if (renderer_->beginFrame(swapchain_)) {
210  renderer_->endFrame();
211  }
212 }
213 
214 } // namespace rendering
215 } // namespace visualization
216 } // namespace cloudViewer
std::function< void(std::shared_ptr< core::Tensor >)> callback
filament::Texture::InternalFormat format
int width
int height
char type
cmdLineReadable * params[]
static FilamentResourceManager & GetResourceManager()
void Configure(const View *view, Scene *scene, int width, int height, int n_channels, bool depth_image, BufferReadyCallback cb) override
void SetDimensions(std::uint32_t width, std::uint32_t height) override
void SetViewport(std::int32_t x, std::int32_t y, std::uint32_t w, std::uint32_t h) override
void CopySettingsFrom(const FilamentView &other)
void SetShadowing(bool enabled, ShadowType type) override
std::function< void(const Buffer &)> BufferReadyCallback
#define LogWarning(...)
Definition: Logging.h:72
#define LogDebug(...)
Definition: Logging.h:90
void ReadPixelsCallback(void *buffer, size_t buffer_size, void *user)
std::tuple< FilamentRenderToBuffer *, FilamentRenderToBuffer::BufferReadyCallback > PBDParams
Generic file read and write utility for python interface.
float float_t