ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TriangleMeshBuffers.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 // 4068: Filament has some clang-specific vectorizing pragma's that MSVC flags
9 // 4146: Filament's utils/algorithm.h utils::details::ctz() tries to negate
10 // an unsigned int.
11 // 4293: Filament's utils/algorithm.h utils::details::clz() does strange
12 // things with MSVC. Somehow sizeof(unsigned int) > 4, but its size is
13 // 32 so that x >> 32 gives a warning. (Or maybe the compiler can't
14 // determine the if statement does not run.)
15 #ifdef _MSC_VER
16 #pragma warning(push)
17 #pragma warning(disable : 4068 4146 4293)
18 #endif // _MSC_VER
19 
20 #include <filament/Engine.h>
21 #include <filament/IndexBuffer.h>
22 #include <filament/MaterialEnums.h>
23 #include <filament/Scene.h>
24 #include <filament/TransformManager.h>
25 #include <filament/VertexBuffer.h>
26 #include <geometry/SurfaceOrientation.h>
27 
28 #ifdef _MSC_VER
29 #pragma warning(pop)
30 #endif // _MSC_VER
31 
32 #include <ecvBBox.h>
33 #include <ecvMesh.h>
34 
35 #include <map>
36 
41 
42 using namespace filament;
43 
44 namespace cloudViewer {
45 namespace visualization {
46 namespace rendering {
47 
48 namespace {
49 
50 struct BaseVertex {
51  math::float3 position = {0.f, 0.f, 0.f};
52  math::quatf tangent = {0.f, 0.f, 0.f, 1.f};
53 };
54 
55 struct ColoredVertex {
56  math::float3 position = {0.f, 0.f, 0.f};
57  math::quatf tangent = {0.f, 0.f, 0.f, 1.f};
58  math::float4 color = {0.5f, 0.5f, 0.5f, 1.f};
59 };
60 
61 struct TexturedVertex {
62  math::float3 position = {0.f, 0.f, 0.f};
63  math::quatf tangent = {0.f, 0.f, 0.f, 1.f};
64  math::float4 color = {0.5f, 0.5f, 0.5f, 1.f};
65  math::float2 uv = {0.f, 0.f};
66 };
67 
68 template <typename VertexType>
69 void SetVertexPosition(VertexType& vertex, const Eigen::Vector3d& pos) {
70  auto float_pos = pos.cast<float>();
71  vertex.position.x = float_pos(0);
72  vertex.position.y = float_pos(1);
73  vertex.position.z = float_pos(2);
74 }
75 
76 template <typename VertexType>
77 void SetVertexColor(VertexType& vertex, const Eigen::Vector3d& c) {
78  auto float_color = c.cast<float>();
79  vertex.color.x = float_color(0);
80  vertex.color.y = float_color(1);
81  vertex.color.z = float_color(2);
82 }
83 
84 template <typename VertexType>
85 void SetVertexUV(VertexType& vertex, const Eigen::Vector2d& UV) {
86  auto float_uv = UV.cast<float>();
87  vertex.uv.x = float_uv(0);
88  vertex.uv.y = float_uv(1);
89 }
90 
91 template <typename VertexType>
92 std::uint32_t GetVertexPositionOffset() {
93  return offsetof(VertexType, position);
94 }
95 
96 template <typename VertexType>
97 std::uint32_t GetVertexTangentOffset() {
98  return offsetof(VertexType, tangent);
99 }
100 
101 template <typename VertexType>
102 std::uint32_t GetVertexColorOffset() {
103  return offsetof(VertexType, color);
104 }
105 
106 template <typename VertexType>
107 std::uint32_t GetVertexUVOffset() {
108  return offsetof(VertexType, uv);
109 }
110 
111 template <typename VertexType>
112 std::uint32_t GetVertexStride() {
113  return sizeof(VertexType);
114 }
115 
116 VertexBuffer* BuildFilamentVertexBuffer(filament::Engine& engine,
117  const std::uint32_t vertices_count,
118  const std::uint32_t stride,
119  bool has_uvs,
120  bool has_colors) {
121  // For CUSTOM0 explanation, see FilamentGeometryBuffersBuilder.cpp
122  // Note, that TANGENTS and CUSTOM0 is pointing on same data in buffer
123  auto builder =
124  VertexBuffer::Builder()
125  .bufferCount(1)
126  .vertexCount(vertices_count)
127  .attribute(VertexAttribute::POSITION, 0,
128  VertexBuffer::AttributeType::FLOAT3,
129  GetVertexPositionOffset<TexturedVertex>(),
130  stride)
131  .normalized(VertexAttribute::TANGENTS)
132  .attribute(VertexAttribute::TANGENTS, 0,
133  VertexBuffer::AttributeType::FLOAT4,
134  GetVertexTangentOffset<TexturedVertex>(), stride)
135  .attribute(VertexAttribute::CUSTOM0, 0,
136  VertexBuffer::AttributeType::FLOAT4,
137  GetVertexTangentOffset<TexturedVertex>(),
138  stride);
139 
140  if (has_colors) {
141  builder.normalized(VertexAttribute::COLOR)
142  .attribute(VertexAttribute::COLOR, 0,
143  VertexBuffer::AttributeType::FLOAT4,
144  GetVertexColorOffset<TexturedVertex>(), stride);
145  }
146 
147  if (has_uvs) {
148  builder.attribute(VertexAttribute::UV0, 0,
149  VertexBuffer::AttributeType::FLOAT2,
150  GetVertexUVOffset<TexturedVertex>(), stride);
151  }
152 
153  return builder.build(engine);
154 }
155 
156 struct vbdata {
157  size_t byte_count = 0;
158  size_t bytes_to_copy = 0;
159  void* bytes = nullptr;
160  size_t vertices_count = 0;
161 };
162 
163 struct ibdata {
164  size_t byte_count = 0;
165  GeometryBuffersBuilder::IndexType* bytes = nullptr;
166  size_t stride = 0;
167 };
168 
169 // Transfers ownership on return for vbdata.bytes and ibdata.bytes
170 std::tuple<vbdata, ibdata> CreatePlainBuffers(const math::quatf* tangents,
171  const ccMesh& geometry) {
172  vbdata vertex_data;
173  ibdata index_data;
174 
175  vertex_data.vertices_count = geometry.getVerticeSize();
176  vertex_data.byte_count = vertex_data.vertices_count * sizeof(BaseVertex);
177  vertex_data.bytes_to_copy = vertex_data.byte_count;
178  vertex_data.bytes = malloc(vertex_data.byte_count);
179 
180  const BaseVertex kDefault;
181  auto plain_vertices = static_cast<BaseVertex*>(vertex_data.bytes);
182  for (size_t i = 0; i < vertex_data.vertices_count; ++i) {
183  BaseVertex& element = plain_vertices[i];
184 
185  SetVertexPosition(element, geometry.getVertice(i));
186  if (tangents != nullptr) {
187  element.tangent = tangents[i];
188  } else {
189  element.tangent = kDefault.tangent;
190  }
191  }
192 
193  index_data.stride = sizeof(GeometryBuffersBuilder::IndexType);
194  index_data.byte_count = geometry.size() * 3 * index_data.stride;
195  index_data.bytes = static_cast<GeometryBuffersBuilder::IndexType*>(
196  malloc(index_data.byte_count));
197  for (size_t i = 0; i < geometry.size(); ++i) {
198  const auto& triangle = geometry.getTriangle(i);
199  index_data.bytes[3 * i] = triangle(0);
200  index_data.bytes[3 * i + 1] = triangle(1);
201  index_data.bytes[3 * i + 2] = triangle(2);
202  }
203 
204  return std::make_tuple(vertex_data, index_data);
205 }
206 
207 // Transfers ownership on return for vbdata.bytes and ibdata.bytes
208 std::tuple<vbdata, ibdata> CreateColoredBuffers(const math::quatf* tangents,
209  const ccMesh& geometry) {
210  vbdata vertex_data;
211  ibdata index_data;
212 
213  vertex_data.vertices_count = geometry.getVerticeSize();
214  vertex_data.byte_count =
215  vertex_data.vertices_count * sizeof(TexturedVertex);
216  vertex_data.bytes_to_copy = vertex_data.byte_count;
217  vertex_data.bytes = malloc(vertex_data.byte_count);
218 
219  const TexturedVertex kDefault;
220  auto vertices = static_cast<TexturedVertex*>(vertex_data.bytes);
221  for (size_t i = 0; i < vertex_data.vertices_count; ++i) {
222  TexturedVertex& element = vertices[i];
223 
224  SetVertexPosition(element, geometry.getVertice(i));
225  if (tangents != nullptr) {
226  element.tangent = tangents[i];
227  } else {
228  element.tangent = kDefault.tangent;
229  }
230 
231  if (geometry.hasColors()) {
232  SetVertexColor(element, geometry.getVertexColor(i));
233  } else {
234  element.color = kDefault.color;
235  }
236  }
237 
238  index_data.stride = sizeof(GeometryBuffersBuilder::IndexType);
239  index_data.byte_count = geometry.size() * 3 * index_data.stride;
240  index_data.bytes = static_cast<GeometryBuffersBuilder::IndexType*>(
241  malloc(index_data.byte_count));
242  for (size_t i = 0; i < geometry.size(); ++i) {
243  const auto& triangle = geometry.getTriangle(i);
244  index_data.bytes[3 * i] = triangle(0);
245  index_data.bytes[3 * i + 1] = triangle(1);
246  index_data.bytes[3 * i + 2] = triangle(2);
247  }
248 
249  return std::make_tuple(vertex_data, index_data);
250 }
251 
252 // Transfers ownership on return for vbdata.bytes and ibdata.bytes
253 std::tuple<vbdata, ibdata> CreateTexturedBuffers(const math::quatf* tangents,
254  const ccMesh& geometry) {
255  vbdata vertex_data;
256  ibdata index_data;
257 
258  struct LookupKey {
259  LookupKey() = default;
260  explicit LookupKey(const Eigen::Vector3d& pos,
261  const Eigen::Vector2d& uv) {
262  values[0] = pos.x();
263  values[1] = pos.y();
264  values[2] = pos.z();
265  values[3] = uv.x();
266  values[4] = uv.y();
267  }
268 
269  // Not necessarily transitive for points within kEpsilon.
270  // TODO: does this break sort and map?
271  bool operator<(const LookupKey& other) const {
272  for (int i = 0; i < 5; ++i) {
273  double diff = abs(values[i] - other.values[i]);
274  if (diff > kEpsilon) {
275  return values[i] < other.values[i];
276  }
277  }
278 
279  return false;
280  }
281 
282  const double kEpsilon = 0.00001;
283  double values[5] = {0};
284  };
285  // < real index , source index >
286  std::map<LookupKey, std::pair<GeometryBuffersBuilder::IndexType,
287  GeometryBuffersBuilder::IndexType>>
288  index_lookup;
289 
290  index_data.stride = sizeof(GeometryBuffersBuilder::IndexType);
291  index_data.byte_count = geometry.size() * 3 * index_data.stride;
292  index_data.bytes = static_cast<GeometryBuffersBuilder::IndexType*>(
293  malloc(index_data.byte_count));
294 
295  vertex_data.byte_count = geometry.size() * 3 * sizeof(TexturedVertex);
296  vertex_data.bytes = malloc(vertex_data.byte_count);
297 
298  GeometryBuffersBuilder::IndexType free_idx = 0;
299  GeometryBuffersBuilder::IndexType uv_idx = 0;
300  auto textured_vertices = static_cast<TexturedVertex*>(vertex_data.bytes);
301 
302  const TexturedVertex kDefault;
303  for (size_t i = 0; i < geometry.size(); ++i) {
304  const auto& triangle = geometry.getTriangle(i);
305 
306  for (size_t j = 0; j < 3; ++j) {
307  GeometryBuffersBuilder::IndexType index = triangle(j);
308 
309  auto uv = geometry.triangle_uvs_[uv_idx];
310  auto pos = geometry.getVertice(index);
311 
312  LookupKey lookup_key(pos, uv);
313  auto found = index_lookup.find(lookup_key);
314  if (found != index_lookup.end()) {
315  index = found->second.first;
316  } else {
317  index = free_idx;
318  GeometryBuffersBuilder::IndexType source_idx = triangle(j);
319 
320  index_lookup[lookup_key] = {free_idx, source_idx};
321  ++free_idx;
322 
323  TexturedVertex& element = textured_vertices[index];
324  SetVertexPosition(element, pos);
325  if (tangents != nullptr) {
326  element.tangent = tangents[source_idx];
327  } else {
328  element.tangent = kDefault.tangent;
329  }
330 
331  SetVertexUV(element, uv);
332 
333  if (geometry.hasColors()) {
334  SetVertexColor(element,
335  geometry.getVertexColor(source_idx));
336  } else {
337  element.color = kDefault.color;
338  }
339  }
340 
341  index_data.bytes[3 * i + j] = index;
342 
343  ++uv_idx;
344  }
345  }
346 
347  vertex_data.vertices_count = free_idx;
348  vertex_data.bytes_to_copy =
349  vertex_data.vertices_count * sizeof(TexturedVertex);
350 
351  return std::make_tuple(vertex_data, index_data);
352 }
353 
354 } // namespace
355 
356 TriangleMeshBuffersBuilder::TriangleMeshBuffersBuilder(const ccMesh& geometry)
357  : geometry_(geometry) {}
358 
359 RenderableManager::PrimitiveType TriangleMeshBuffersBuilder::GetPrimitiveType()
360  const {
361  return RenderableManager::PrimitiveType::TRIANGLES;
362 }
363 
365  auto& engine = EngineInstance::GetInstance();
366  auto& resource_mgr = EngineInstance::GetResourceManager();
367 
368  const size_t n_vertices = geometry_.getVerticeSize();
369 
370  math::quatf* float4v_tangents = nullptr;
371  if (geometry_.hasNormals()) {
372  // Converting vertex normals to float base
373  std::vector<Eigen::Vector3f> normals;
374  normals.resize(n_vertices);
375  for (size_t i = 0; i < n_vertices; ++i) {
376  normals[i] = geometry_.getVertexNormal(i).cast<float>();
377  }
378 
379  // Converting normals to Filament type - quaternions
380  const size_t tangents_byte_count = n_vertices * 4 * sizeof(float);
381  float4v_tangents =
382  static_cast<math::quatf*>(malloc(tangents_byte_count));
383  auto orientation = filament::geometry::SurfaceOrientation::Builder()
384  .vertexCount(n_vertices)
385  .normals(reinterpret_cast<math::float3*>(
386  normals.data()))
387  .build();
388  orientation->getQuats(float4v_tangents, n_vertices);
389  }
390 
391  // NOTE: Both default lit and unlit material shaders require per-vertex
392  // colors so we unconditionally assume the triangle mesh has color.
393  const bool has_colors = true;
394  bool has_uvs = geometry_.hasTriangleUvs();
395 
396  // We take ownership of vbdata.bytes and ibdata.bytes here.
397  std::tuple<vbdata, ibdata> buffers_data;
398  size_t stride = sizeof(BaseVertex);
399  if (has_uvs) {
400  buffers_data = CreateTexturedBuffers(float4v_tangents, geometry_);
401  stride = sizeof(TexturedVertex);
402  } else if (has_colors) {
403  buffers_data = CreateColoredBuffers(float4v_tangents, geometry_);
404  stride = sizeof(TexturedVertex);
405  has_uvs = true;
406  } else {
407  buffers_data = CreatePlainBuffers(float4v_tangents, geometry_);
408  }
409 
410  free(float4v_tangents);
411 
412  const vbdata& vertex_data = std::get<0>(buffers_data);
413  const ibdata& index_data = std::get<1>(buffers_data);
414 
415  VertexBuffer* vbuf = nullptr;
416  vbuf = BuildFilamentVertexBuffer(
417  engine, std::uint32_t(vertex_data.vertices_count),
418  std::uint32_t(stride), has_uvs, has_colors);
419 
420  VertexBufferHandle vb_handle;
421  if (vbuf) {
422  vb_handle = resource_mgr.AddVertexBuffer(vbuf);
423  } else {
424  free(vertex_data.bytes);
425  free(index_data.bytes);
426 
427  return {};
428  }
429 
430  // Gives ownership of vertexData.bytes to VertexBuffer, which will
431  // be deallocated later with DeallocateBuffer.
432  VertexBuffer::BufferDescriptor vb_descriptor(vertex_data.bytes,
433  vertex_data.bytes_to_copy);
434  vb_descriptor.setCallback(GeometryBuffersBuilder::DeallocateBuffer);
435  vbuf->setBufferAt(engine, 0, std::move(vb_descriptor));
436 
437  auto ib_handle = resource_mgr.CreateIndexBuffer(
438  index_data.byte_count / index_data.stride, index_data.stride);
439  auto ibuf = resource_mgr.GetIndexBuffer(ib_handle).lock();
440 
441  // Gives ownership of indexData.bytes to IndexBuffer, which will
442  // be deallocated later with DeallocateBuffer.
443  IndexBuffer::BufferDescriptor ib_descriptor(index_data.bytes,
444  index_data.byte_count);
445  ib_descriptor.setCallback(GeometryBuffersBuilder::DeallocateBuffer);
446  ibuf->setBuffer(engine, std::move(ib_descriptor));
447 
448  return std::make_tuple(vb_handle, ib_handle, IndexBufferHandle());
449 }
450 
452  auto geometry_aabb = geometry_.GetAxisAlignedBoundingBox();
453 
454  const filament::math::float3 min(geometry_aabb.minCorner().x,
455  geometry_aabb.minCorner().y,
456  geometry_aabb.minCorner().z);
457  const filament::math::float3 max(geometry_aabb.maxCorner().x,
458  geometry_aabb.maxCorner().y,
459  geometry_aabb.maxCorner().z);
460 
461  Box aabb;
462  aabb.set(min, max);
463 
464  return aabb;
465 }
466 
468  const t::geometry::TriangleMesh& geometry)
469  : geometry_(geometry) {
470  // Make sure geometry is on GPU
471  auto pts = geometry.GetVertexPositions();
472  if (pts.IsCUDA()) {
474  "GPU resident triangle meshes are not currently supported for "
475  "visualization. Copying data to CPU.");
476  geometry_ = geometry.To(core::Device("CPU:0"));
477  }
478 
479  // Now make sure data types are Float32
480  if (pts.GetDtype() != core::Float32) {
482  "Tensor triangle mesh vertices must have DType of Float32 not "
483  "{}. Converting.",
484  pts.GetDtype().ToString());
485  geometry_.GetVertexPositions() = pts.To(core::Float32);
486  }
487  if (geometry_.HasVertexNormals() &&
488  geometry_.GetVertexNormals().GetDtype() != core::Float32) {
489  auto normals = geometry_.GetVertexNormals();
491  "Tensor triangle mesh normals must have DType of Float32 not "
492  "{}. Converting.",
493  normals.GetDtype().ToString());
494  geometry_.GetVertexNormals() = normals.To(core::Float32);
495  }
496  if (geometry_.HasVertexColors() &&
497  geometry_.GetVertexColors().GetDtype() != core::Float32) {
498  auto colors = geometry_.GetVertexColors();
499 
501  "Tensor triangle mesh colors must have DType of Float32 not "
502  "{}. Converting.",
503  colors.GetDtype().ToString());
504  geometry_.GetVertexColors() = colors.To(core::Float32);
505  // special case for Uint8
506  if (colors.GetDtype() == core::UInt8) {
507  geometry_.GetVertexColors() = geometry_.GetVertexColors() / 255.0f;
508  }
509  }
510 }
511 
512 RenderableManager::PrimitiveType TMeshBuffersBuilder::GetPrimitiveType() const {
513  return RenderableManager::PrimitiveType::TRIANGLES;
514 }
515 
517  auto& engine = EngineInstance::GetInstance();
518  auto& resource_mgr = EngineInstance::GetResourceManager();
519 
520  bool need_duplicate_vertices = geometry_.HasTriangleNormals() ||
521  geometry_.HasTriangleColors() ||
522  geometry_.HasTriangleAttr("texture_uvs");
523  const auto& points = geometry_.GetVertexPositions();
524  const auto& indices = geometry_.GetTriangleIndices();
525  const auto indices_64 = indices.To(core::Int64); // for Tensor indexing
526  const size_t n_vertices = need_duplicate_vertices ? indices.GetLength() * 3
527  : points.GetLength();
528 
529  // We use CUSTOM0 for tangents along with TANGENTS attribute
530  // because Filament would optimize out anything about normals and lightning
531  // from unlit materials. But our shader for normals visualizing is unlit, so
532  // we need to use this workaround.
533  VertexBuffer* vbuf = VertexBuffer::Builder()
534  .bufferCount(4)
535  .vertexCount(uint32_t(n_vertices))
536  .attribute(VertexAttribute::POSITION, 0,
537  VertexBuffer::AttributeType::FLOAT3)
538  .normalized(VertexAttribute::COLOR)
539  .attribute(VertexAttribute::COLOR, 1,
540  VertexBuffer::AttributeType::FLOAT3)
541  .normalized(VertexAttribute::TANGENTS)
542  .attribute(VertexAttribute::TANGENTS, 2,
543  VertexBuffer::AttributeType::FLOAT4)
544  .attribute(VertexAttribute::CUSTOM0, 2,
545  VertexBuffer::AttributeType::FLOAT4)
546  .attribute(VertexAttribute::UV0, 3,
547  VertexBuffer::AttributeType::FLOAT2)
548  .build(engine);
549 
550  VertexBufferHandle vb_handle;
551  if (vbuf) {
552  vb_handle = resource_mgr.AddVertexBuffer(vbuf);
553  } else {
554  return {};
555  }
556 
557  // Vertices
558  const size_t vertex_array_size = n_vertices * 3 * sizeof(float);
559  float* vertex_array = static_cast<float*>(malloc(vertex_array_size));
560  if (need_duplicate_vertices) {
561  core::Tensor dup_vertices = points.IndexGet(
562  {indices_64.Reshape({static_cast<long>(n_vertices)})});
563  memcpy(vertex_array, dup_vertices.GetDataPtr(), vertex_array_size);
564  } else {
565  memcpy(vertex_array, points.GetDataPtr(), vertex_array_size);
566  }
567  VertexBuffer::BufferDescriptor pts_descriptor(
568  vertex_array, vertex_array_size,
570  vbuf->setBufferAt(engine, 0, std::move(pts_descriptor));
571 
572  // Prepare color array
573  const size_t color_array_size = n_vertices * 3 * sizeof(float);
574  float* color_array = static_cast<float*>(malloc(color_array_size));
575  if (geometry_.HasVertexColors()) {
576  if (need_duplicate_vertices) {
577  core::Tensor dup_colors = geometry_.GetVertexColors().IndexGet(
578  {indices_64.Reshape({static_cast<long>(n_vertices)})});
579  memcpy(color_array, dup_colors.GetDataPtr(), color_array_size);
580  } else {
581  memcpy(color_array, geometry_.GetVertexColors().GetDataPtr(),
582  color_array_size);
583  }
584  } else if (geometry_.HasTriangleColors()) {
585  const auto& colors = geometry_.GetTriangleColors();
586  core::Tensor dup_colors = core::Tensor::Empty(
587  {static_cast<long>(n_vertices), 3}, core::Float32);
588  dup_colors.Slice(0, 0, n_vertices, 3) = colors;
589  dup_colors.Slice(0, 1, n_vertices, 3) = colors;
590  dup_colors.Slice(0, 2, n_vertices, 3) = colors;
591  memcpy(color_array, dup_colors.GetDataPtr(), color_array_size);
592  } else {
593  for (size_t i = 0; i < n_vertices * 3; ++i) {
594  color_array[i] = 0.5f;
595  }
596  }
597  VertexBuffer::BufferDescriptor color_descriptor(
598  color_array, color_array_size,
600  vbuf->setBufferAt(engine, 1, std::move(color_descriptor));
601 
602  // Prepare normal array
603  const size_t normal_array_size = n_vertices * 4 * sizeof(float);
604  float* normal_array = static_cast<float*>(malloc(normal_array_size));
605  if (geometry_.HasVertexNormals()) {
606  if (need_duplicate_vertices) {
607  core::Tensor dup_normals = geometry_.GetVertexNormals().IndexGet(
608  {indices_64.Reshape({static_cast<long>(n_vertices)})});
609  auto orientation =
610  filament::geometry::SurfaceOrientation::Builder()
611  .vertexCount(n_vertices)
612  .normals(reinterpret_cast<const math::float3*>(
613  dup_normals.GetDataPtr()))
614  .build();
615  orientation->getQuats(reinterpret_cast<math::quatf*>(normal_array),
616  n_vertices);
617  delete orientation;
618  } else {
619  const auto& normals = geometry_.GetVertexNormals();
620  // Converting normals to Filament type - quaternions
621  auto orientation =
622  filament::geometry::SurfaceOrientation::Builder()
623  .vertexCount(n_vertices)
624  .normals(reinterpret_cast<const math::float3*>(
625  normals.GetDataPtr()))
626  .build();
627  orientation->getQuats(reinterpret_cast<math::quatf*>(normal_array),
628  n_vertices);
629  delete orientation;
630  }
631  } else if (geometry_.HasTriangleNormals()) {
632  const auto& normals = geometry_.GetTriangleNormals();
633  core::Tensor dup_normals = core::Tensor::Empty(
634  {static_cast<long>(n_vertices), 3}, core::Float32);
635  dup_normals.Slice(0, 0, n_vertices, 3) = normals;
636  dup_normals.Slice(0, 1, n_vertices, 3) = normals;
637  dup_normals.Slice(0, 2, n_vertices, 3) = normals;
638  auto orientation =
639  filament::geometry::SurfaceOrientation::Builder()
640  .vertexCount(n_vertices)
641  .normals(reinterpret_cast<const math::float3*>(
642  dup_normals.GetDataPtr()))
643  .build();
644  orientation->getQuats(reinterpret_cast<math::quatf*>(normal_array),
645  n_vertices);
646  delete orientation;
647  } else {
648  float* normal_ptr = normal_array;
649  for (size_t i = 0; i < n_vertices; ++i) {
650  *normal_ptr++ = 0.f;
651  *normal_ptr++ = 0.f;
652  *normal_ptr++ = 0.f;
653  *normal_ptr++ = 1.f;
654  }
655  }
656  VertexBuffer::BufferDescriptor normals_descriptor(
657  normal_array, normal_array_size,
659  vbuf->setBufferAt(engine, 2, std::move(normals_descriptor));
660 
661  // Prepare UV array
662  const size_t uv_array_size = n_vertices * 2 * sizeof(float);
663  float* uv_array = static_cast<float*>(malloc(uv_array_size));
664  if (geometry_.HasVertexAttr("texture_uvs")) {
665  if (need_duplicate_vertices) {
666  core::Tensor dup_uvs =
667  geometry_.GetVertexAttr("texture_uvs")
668  .IndexGet({indices_64.Reshape(
669  {static_cast<long>(n_vertices)})});
670  memcpy(uv_array, dup_uvs.GetDataPtr(), uv_array_size);
671  } else {
672  memcpy(uv_array,
673  geometry_.GetVertexAttr("texture_uvs").GetDataPtr(),
674  uv_array_size);
675  }
676  } else if (geometry_.HasTriangleAttr("texture_uvs")) {
677  memcpy(uv_array, geometry_.GetTriangleAttr("texture_uvs").GetDataPtr(),
678  uv_array_size);
679  } else {
680  memset(uv_array, 0x0, uv_array_size);
681  }
682  VertexBuffer::BufferDescriptor uv_descriptor(
683  uv_array, uv_array_size, GeometryBuffersBuilder::DeallocateBuffer);
684  vbuf->setBufferAt(engine, 3, std::move(uv_descriptor));
685 
686  // Create the index buffer
687  // NOTE: Filament supports both UInt16 and UInt32 triangle indices.
688  // Currently, however, we only support 32bit indices. This may change in the
689  // future.
690  const uint32_t n_indices =
691  need_duplicate_vertices ? n_vertices : indices.GetLength() * 3;
692  const size_t n_bytes = n_indices * sizeof(uint32_t);
693  auto* uint_indices = static_cast<uint32_t*>(malloc(n_bytes));
694  if (need_duplicate_vertices) {
695  std::iota(uint_indices, uint_indices + n_vertices, 0);
696  } else {
697  // NOTE: if indices is already UInt32 the following is as no-op
698  const auto indices_32 = indices.To(core::UInt32);
699  memcpy(uint_indices, indices_32.GetDataPtr(), n_bytes);
700  }
701  auto ib_handle =
702  resource_mgr.CreateIndexBuffer(n_indices, sizeof(uint32_t));
703  auto ibuf = resource_mgr.GetIndexBuffer(ib_handle).lock();
704  IndexBuffer::BufferDescriptor indices_descriptor(
705  uint_indices, n_bytes, GeometryBuffersBuilder::DeallocateBuffer);
706  ibuf->setBuffer(engine, std::move(indices_descriptor));
707  IndexBufferHandle downsampled_handle;
708 
709  return std::make_tuple(vb_handle, ib_handle, downsampled_handle);
710 }
711 
713  auto min_bounds = geometry_.GetMinBound();
714  auto max_bounds = geometry_.GetMaxBound();
715  auto* min_bounds_float = min_bounds.GetDataPtr<float>();
716  auto* max_bounds_float = max_bounds.GetDataPtr<float>();
717 
718  const filament::math::float3 min_pt(
719  min_bounds_float[0], min_bounds_float[1], min_bounds_float[2]);
720  const filament::math::float3 max_pt(
721  max_bounds_float[0], max_bounds_float[1], max_bounds_float[2]);
722 
723  Box aabb;
724  aabb.set(min_pt, max_pt);
725  if (aabb.isEmpty()) {
726  const filament::math::float3 offset(0.1, 0.1, 0.1);
727  aabb.set(min_pt - offset, max_pt + offset);
728  }
729 
730  return aabb;
731 }
732 
733 } // namespace rendering
734 } // namespace visualization
735 } // namespace cloudViewer
bool has_colors
int offset
int points
size_t byte_count
size_t bytes_to_copy
math::float2 uv
math::quatf tangent
size_t vertices_count
size_t stride
void * bytes
math::float4 color
math::float3 position
Triangular mesh.
Definition: ecvMesh.h:35
std::vector< Eigen::Vector2d > triangle_uvs_
List of uv coordinates per triangle.
Definition: ecvMesh.h:625
bool hasColors() const override
Returns whether colors are enabled or not.
Eigen::Vector3d getVertice(size_t index) const
virtual ccBBox GetAxisAlignedBoundingBox() const override
Returns an axis-aligned bounding box of the geometry.
unsigned int getVerticeSize() const
Eigen::Vector3d getVertexColor(size_t index) const
bool hasNormals() const override
Returns whether normals are enabled or not.
virtual unsigned size() const override
Returns the number of triangles.
Eigen::Vector3i getTriangle(size_t index) const
Eigen::Vector3d getVertexNormal(size_t index) const
bool hasTriangleUvs() const
Definition: ecvMesh.h:717
int64_t GetLength() const
Definition: Tensor.h:1125
Dtype GetDtype() const
Definition: Tensor.h:1164
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
Definition: Tensor.cpp:905
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
Tensor Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Definition: Tensor.cpp:857
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
A triangle mesh contains vertices and triangles.
Definition: TriangleMesh.h:98
const TensorMap & GetVertexAttr() const
Getter for vertex_attr_ TensorMap. Used in Pybind.
Definition: TriangleMesh.h:133
TriangleMesh To(const core::Device &device, bool copy=false) const
bool HasVertexAttr(const std::string &key) const
Definition: TriangleMesh.h:314
bool HasTriangleAttr(const std::string &key) const
Definition: TriangleMesh.h:343
const TensorMap & GetTriangleAttr() const
Getter for triangle_attr_ TensorMap. Used in Pybind.
Definition: TriangleMesh.h:159
static FilamentResourceManager & GetResourceManager()
static void DeallocateBuffer(void *buffer, size_t size, void *user_ptr)
std::tuple< VertexBufferHandle, IndexBufferHandle, IndexBufferHandle > Buffers
filament::RenderableManager::PrimitiveType GetPrimitiveType() const override
TMeshBuffersBuilder(const t::geometry::TriangleMesh &geometry)
filament::RenderableManager::PrimitiveType GetPrimitiveType() const override
double colors[3]
double normals[3]
#define LogWarning(...)
Definition: Logging.h:72
int min(int a, int b)
Definition: cutil_math.h:53
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
int max(int a, int b)
Definition: cutil_math.h:48
const Dtype Int64
Definition: Dtype.cpp:47
const Dtype UInt32
Definition: Dtype.cpp:50
const Dtype UInt8
Definition: Dtype.cpp:48
const Dtype Float32
Definition: Dtype.cpp:42
constexpr bool operator<(const optional< T > &x, const optional< T > &y)
Definition: Optional.h:625
REHandle< EntityType::IndexBuffer > IndexBufferHandle
Generic file read and write utility for python interface.
#define offsetof(STRUCTURE, FIELD)
Definition: sqlite3.c:14241