Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
VoxelBlockGridImpl.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2024 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8#include <atomic>
9#include <cmath>
10
11#include "open3d/core/Dtype.h"
13#include "open3d/core/Tensor.h"
15#ifndef __CUDACC__
17#endif
18#if defined(SYCL_LANGUAGE_VERSION)
20#endif
21#if defined(__CUDACC__)
23#endif
29
30namespace open3d {
31namespace t {
32namespace geometry {
33namespace kernel {
34namespace voxel_grid {
35
36using index_t = int;
38
39#if defined(__CUDACC__)
40void GetVoxelCoordinatesAndFlattenedIndicesCUDA
41#elif defined(SYCL_LANGUAGE_VERSION)
42void GetVoxelCoordinatesAndFlattenedIndicesSYCL
43#else
45#endif
46 (const core::Tensor& buf_indices,
47 const core::Tensor& block_keys,
48 core::Tensor& voxel_coords,
49 core::Tensor& flattened_indices,
50 index_t resolution,
51 float voxel_size) {
52 core::Device device = buf_indices.GetDevice();
53
54 const index_t* buf_indices_ptr = buf_indices.GetDataPtr<index_t>();
55 const index_t* block_key_ptr = block_keys.GetDataPtr<index_t>();
56
57 float* voxel_coords_ptr = voxel_coords.GetDataPtr<float>();
58 int64_t* flattened_indices_ptr = flattened_indices.GetDataPtr<int64_t>();
59
60 index_t n = flattened_indices.GetLength();
61 ArrayIndexer voxel_indexer({resolution, resolution, resolution});
62 index_t resolution3 = resolution * resolution * resolution;
63
64 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t workload_idx) {
65 index_t block_idx = buf_indices_ptr[workload_idx / resolution3];
66 index_t voxel_idx = workload_idx % resolution3;
67
68 index_t block_key_offset = block_idx * 3;
69 index_t xb = block_key_ptr[block_key_offset + 0];
70 index_t yb = block_key_ptr[block_key_offset + 1];
71 index_t zb = block_key_ptr[block_key_offset + 2];
72
73 index_t xv, yv, zv;
74 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
75
76 float x = (xb * resolution + xv) * voxel_size;
77 float y = (yb * resolution + yv) * voxel_size;
78 float z = (zb * resolution + zv) * voxel_size;
79
80 flattened_indices_ptr[workload_idx] =
81 block_idx * resolution3 + voxel_idx;
82
83 index_t voxel_coords_offset = workload_idx * 3;
84 voxel_coords_ptr[voxel_coords_offset + 0] = x;
85 voxel_coords_ptr[voxel_coords_offset + 1] = y;
86 voxel_coords_ptr[voxel_coords_offset + 2] = z;
87 });
88}
89
92 index_t yo,
93 index_t zo,
94 index_t curr_block_idx,
95 index_t resolution,
96 const ArrayIndexer& nb_block_masks_indexer,
97 const ArrayIndexer& nb_block_indices_indexer) {
98 index_t xn = (xo + resolution) % resolution;
99 index_t yn = (yo + resolution) % resolution;
100 index_t zn = (zo + resolution) % resolution;
101
102 index_t dxb = Sign(xo - xn);
103 index_t dyb = Sign(yo - yn);
104 index_t dzb = Sign(zo - zn);
105
106 index_t nb_idx = (dxb + 1) + (dyb + 1) * 3 + (dzb + 1) * 9;
107
108 bool block_mask_i =
109 *nb_block_masks_indexer.GetDataPtr<bool>(curr_block_idx, nb_idx);
110 if (!block_mask_i) return -1;
111
112 index_t block_idx_i = *nb_block_indices_indexer.GetDataPtr<index_t>(
113 curr_block_idx, nb_idx);
114
115 return (((block_idx_i * resolution) + zn) * resolution + yn) * resolution +
116 xn;
117}
118
119template <typename tsdf_t>
121 const tsdf_t* tsdf_base_ptr,
122 index_t xo,
123 index_t yo,
124 index_t zo,
125 index_t curr_block_idx,
126 float* n,
127 index_t resolution,
128 const ArrayIndexer& nb_block_masks_indexer,
129 const ArrayIndexer& nb_block_indices_indexer) {
130 auto GetLinearIdx = [&] OPEN3D_DEVICE(index_t xo, index_t yo,
131 index_t zo) -> index_t {
132 return DeviceGetLinearIdx(xo, yo, zo, curr_block_idx, resolution,
133 nb_block_masks_indexer,
134 nb_block_indices_indexer);
135 };
136 index_t vxp = GetLinearIdx(xo + 1, yo, zo);
137 index_t vxn = GetLinearIdx(xo - 1, yo, zo);
138 index_t vyp = GetLinearIdx(xo, yo + 1, zo);
139 index_t vyn = GetLinearIdx(xo, yo - 1, zo);
140 index_t vzp = GetLinearIdx(xo, yo, zo + 1);
141 index_t vzn = GetLinearIdx(xo, yo, zo - 1);
142 if (vxp >= 0 && vxn >= 0) n[0] = tsdf_base_ptr[vxp] - tsdf_base_ptr[vxn];
143 if (vyp >= 0 && vyn >= 0) n[1] = tsdf_base_ptr[vyp] - tsdf_base_ptr[vyn];
144 if (vzp >= 0 && vzn >= 0) n[2] = tsdf_base_ptr[vzp] - tsdf_base_ptr[vzn];
145};
146
147template <typename input_depth_t,
148 typename input_color_t,
149 typename tsdf_t,
150 typename weight_t,
151 typename color_t>
152#if defined(__CUDACC__)
153void IntegrateCUDA
154#elif defined(SYCL_LANGUAGE_VERSION)
155void IntegrateSYCL
156#else
158#endif
159 (const core::Tensor& depth,
160 const core::Tensor& color,
161 const core::Tensor& indices,
162 const core::Tensor& block_keys,
163 TensorMap& block_value_map,
164 const core::Tensor& depth_intrinsic,
165 const core::Tensor& color_intrinsic,
166 const core::Tensor& extrinsics,
167 index_t resolution,
168 float voxel_size,
169 float sdf_trunc,
170 float depth_scale,
171 float depth_max) {
172 // Parameters
173 index_t resolution2 = resolution * resolution;
174 index_t resolution3 = resolution2 * resolution;
175
176 TransformIndexer transform_indexer(depth_intrinsic, extrinsics, voxel_size);
177 TransformIndexer colormap_indexer(
178 color_intrinsic,
180
181 ArrayIndexer voxel_indexer({resolution, resolution, resolution});
182
183 ArrayIndexer block_keys_indexer(block_keys, 1);
184 ArrayIndexer depth_indexer(depth, 2);
185 core::Device device = block_keys.GetDevice();
186
187 const index_t* indices_ptr = indices.GetDataPtr<index_t>();
188
189 if (!block_value_map.Contains("tsdf") ||
190 !block_value_map.Contains("weight")) {
191 utility::LogError(
192 "TSDF and/or weight not allocated in blocks, please implement "
193 "customized integration.");
194 }
195 tsdf_t* tsdf_base_ptr = block_value_map.at("tsdf").GetDataPtr<tsdf_t>();
196 weight_t* weight_base_ptr =
197 block_value_map.at("weight").GetDataPtr<weight_t>();
198
199 bool integrate_color =
200 block_value_map.Contains("color") && color.NumElements() > 0;
201 color_t* color_base_ptr = nullptr;
202 ArrayIndexer color_indexer;
203
204 float color_multiplier = 1.0;
205 if (integrate_color) {
206 color_base_ptr = block_value_map.at("color").GetDataPtr<color_t>();
207 color_indexer = ArrayIndexer(color, 2);
208
209 // Float32: [0, 1] -> [0, 255]
210 if (color.GetDtype() == core::Float32) {
211 color_multiplier = 255.0;
212 }
213 }
214
215 index_t n = indices.GetLength() * resolution3;
216 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t workload_idx) {
217 // Natural index (0, N) -> (block_idx, voxel_idx)
218 index_t block_idx = indices_ptr[workload_idx / resolution3];
219 index_t voxel_idx = workload_idx % resolution3;
220
222 // block_idx -> (x_block, y_block, z_block)
223 index_t* block_key_ptr =
224 block_keys_indexer.GetDataPtr<index_t>(block_idx);
225 index_t xb = block_key_ptr[0];
226 index_t yb = block_key_ptr[1];
227 index_t zb = block_key_ptr[2];
228
229 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
230 index_t xv, yv, zv;
231 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
232
233 // coordinate in world (in voxel)
234 index_t x = xb * resolution + xv;
235 index_t y = yb * resolution + yv;
236 index_t z = zb * resolution + zv;
237
238 // coordinate in camera (in voxel -> in meter)
239 float xc, yc, zc, u, v;
240 transform_indexer.RigidTransform(static_cast<float>(x),
241 static_cast<float>(y),
242 static_cast<float>(z), &xc, &yc, &zc);
243
244 // coordinate in image (in pixel)
245 transform_indexer.Project(xc, yc, zc, &u, &v);
246 if (!depth_indexer.InBoundary(u, v)) {
247 return;
248 }
249
250 index_t ui = static_cast<index_t>(u);
251 index_t vi = static_cast<index_t>(v);
252
253 // Associate image workload and compute SDF and
254 // TSDF.
255 float depth =
256 *depth_indexer.GetDataPtr<input_depth_t>(ui, vi) / depth_scale;
257
258 float sdf = depth - zc;
259 if (depth <= 0 || depth > depth_max || zc <= 0 || sdf < -sdf_trunc) {
260 return;
261 }
262 sdf = sdf < sdf_trunc ? sdf : sdf_trunc;
263 sdf /= sdf_trunc;
264
265 index_t linear_idx = block_idx * resolution3 + voxel_idx;
266
267 tsdf_t* tsdf_ptr = tsdf_base_ptr + linear_idx;
268 weight_t* weight_ptr = weight_base_ptr + linear_idx;
269
270 float inv_wsum = 1.0f / (*weight_ptr + 1);
271 float weight = *weight_ptr;
272 *tsdf_ptr = (weight * (*tsdf_ptr) + sdf) * inv_wsum;
273
274 if (integrate_color) {
275 color_t* color_ptr = color_base_ptr + 3 * linear_idx;
276
277 // Unproject ui, vi with depth_intrinsic, then project back with
278 // color_intrinsic
279 float x, y, z;
280 transform_indexer.Unproject(ui, vi, 1.0, &x, &y, &z);
281
282 float uf, vf;
283 colormap_indexer.Project(x, y, z, &uf, &vf);
284 if (color_indexer.InBoundary(uf, vf)) {
285 ui = round(uf);
286 vi = round(vf);
287
288 input_color_t* input_color_ptr =
289 color_indexer.GetDataPtr<input_color_t>(ui, vi);
290
291 for (index_t i = 0; i < 3; ++i) {
292 color_ptr[i] = (weight * color_ptr[i] +
293 input_color_ptr[i] * color_multiplier) *
294 inv_wsum;
295 }
296 }
297 }
298 *weight_ptr = weight + 1;
299 });
300
301#if defined(__CUDACC__)
303#endif
304}
305
306#if defined(__CUDACC__)
307void EstimateRangeCUDA
308#elif defined(SYCL_LANGUAGE_VERSION)
309void EstimateRangeSYCL
310#else
312#endif
313 (const core::Tensor& block_keys,
314 core::Tensor& range_minmax_map,
315 const core::Tensor& intrinsics,
316 const core::Tensor& extrinsics,
317 int h,
318 int w,
319 int down_factor,
320 int64_t block_resolution,
321 float voxel_size,
322 float depth_min,
323 float depth_max,
324 core::Tensor& fragment_buffer) {
325
326 // TODO(wei): reserve it in a reusable buffer
327
328 // Every 2 channels: (min, max)
329 int h_down = h / down_factor;
330 int w_down = w / down_factor;
331 range_minmax_map = core::Tensor({h_down, w_down, 2}, core::Float32,
332 block_keys.GetDevice());
333 NDArrayIndexer range_map_indexer(range_minmax_map, 2);
334
335 // Every 6 channels: (v_min, u_min, v_max, u_max, z_min, z_max)
336 const int fragment_size = 16;
337
338 if (fragment_buffer.GetDataPtr() == 0 ||
339 fragment_buffer.NumElements() == 0) {
340 // Rough heuristic; should tend to overallocate
341 const int reserve_frag_buffer_size =
342 h_down * w_down / (fragment_size * fragment_size) / voxel_size;
343 fragment_buffer = core::Tensor({reserve_frag_buffer_size, 6},
344 core::Float32, block_keys.GetDevice());
345 }
346
347 const int frag_buffer_size = fragment_buffer.NumElements() / 6;
348
349 NDArrayIndexer frag_buffer_indexer(fragment_buffer, 1);
350 NDArrayIndexer block_keys_indexer(block_keys, 1);
351 TransformIndexer w2c_transform_indexer(intrinsics, extrinsics);
352#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
353 core::Tensor count(std::vector<int>{0}, {1}, core::Int32,
354 block_keys.GetDevice());
355 int* count_ptr = count.GetDataPtr<int>();
356#else
357 std::atomic<int> count_atomic(0);
358 std::atomic<int>* count_ptr = &count_atomic;
359#endif
360
361#if defined(__CUDACC__)
362#elif defined(SYCL_LANGUAGE_VERSION)
363 using sycl::max;
364 using sycl::min;
365#else
366 using std::max;
367 using std::min;
368#endif
369
370 // Pass 0: iterate over blocks, fill-in an rendering fragment array
372 block_keys.GetDevice(), block_keys.GetLength(),
373 [=] OPEN3D_DEVICE(int64_t workload_idx) {
374 int* key = block_keys_indexer.GetDataPtr<int>(workload_idx);
375
376 int u_min = w_down - 1, v_min = h_down - 1, u_max = 0,
377 v_max = 0;
378 float z_min = depth_max, z_max = depth_min;
379
380 float xc, yc, zc, u, v;
381
382 // Project 8 corners to low-res image and form a rectangle
383 for (int i = 0; i < 8; ++i) {
384 float xw = (key[0] + ((i & 1) > 0)) * block_resolution *
385 voxel_size;
386 float yw = (key[1] + ((i & 2) > 0)) * block_resolution *
387 voxel_size;
388 float zw = (key[2] + ((i & 4) > 0)) * block_resolution *
389 voxel_size;
390
391 w2c_transform_indexer.RigidTransform(xw, yw, zw, &xc, &yc,
392 &zc);
393 if (zc <= 0) continue;
394
395 // Project to the down sampled image buffer
396 w2c_transform_indexer.Project(xc, yc, zc, &u, &v);
397 u /= down_factor;
398 v /= down_factor;
399
400 v_min = min(static_cast<int>(floorf(v)), v_min);
401 v_max = max(static_cast<int>(ceilf(v)), v_max);
402
403 u_min = min(static_cast<int>(floorf(u)), u_min);
404 u_max = max(static_cast<int>(ceilf(u)), u_max);
405
406 z_min = min(z_min, zc);
407 z_max = max(z_max, zc);
408 }
409
410 v_min = max(0, v_min);
411 v_max = min(h_down - 1, v_max);
412
413 u_min = max(0, u_min);
414 u_max = min(w_down - 1, u_max);
415
416 if (v_min >= v_max || u_min >= u_max || z_min >= z_max) return;
417
418 // Divide the rectangle into small 16x16 fragments
419 int frag_v_count =
420 ceilf(float(v_max - v_min + 1) / float(fragment_size));
421 int frag_u_count =
422 ceilf(float(u_max - u_min + 1) / float(fragment_size));
423
424 int frag_count = frag_v_count * frag_u_count;
425 int frag_count_start = OPEN3D_ATOMIC_ADD(count_ptr, frag_count);
426 int frag_count_end = frag_count_start + frag_count;
427 if (frag_count_end >= frag_buffer_size) {
428 return;
429 }
430
431 int offset = 0;
432 for (int frag_v = 0; frag_v < frag_v_count; ++frag_v) {
433 for (int frag_u = 0; frag_u < frag_u_count;
434 ++frag_u, ++offset) {
435 float* frag_ptr = frag_buffer_indexer.GetDataPtr<float>(
436 frag_count_start + offset);
437 // zmin, zmax
438 frag_ptr[0] = z_min;
439 frag_ptr[1] = z_max;
440
441 // vmin, umin
442 frag_ptr[2] = v_min + frag_v * fragment_size;
443 frag_ptr[3] = u_min + frag_u * fragment_size;
444
445 // vmax, umax
446 frag_ptr[4] = min(frag_ptr[2] + fragment_size - 1,
447 static_cast<float>(v_max));
448 frag_ptr[5] = min(frag_ptr[3] + fragment_size - 1,
449 static_cast<float>(u_max));
450 }
451 }
452 });
453#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
454 int needed_frag_count = count[0].Item<int>();
455#else
456 int needed_frag_count = (*count_ptr).load();
457#endif
458
459 int frag_count = needed_frag_count;
460 if (frag_count >= frag_buffer_size) {
461 utility::LogWarning(
462 "Could not generate full range map; allocated {} fragments but "
463 "needed {}",
464 frag_buffer_size, frag_count);
465 frag_count = frag_buffer_size - 1;
466 } else {
467 utility::LogDebug("EstimateRange Allocated {} fragments and needed {}",
468 frag_buffer_size, frag_count);
469 }
470
471 // Pass 0.5: Fill in range map to prepare for atomic min/max
472 core::ParallelFor(block_keys.GetDevice(), h_down * w_down,
473 [=] OPEN3D_DEVICE(int64_t workload_idx) {
474 int v = workload_idx / w_down;
475 int u = workload_idx % w_down;
476 float* range_ptr =
477 range_map_indexer.GetDataPtr<float>(u, v);
478 range_ptr[0] = depth_max;
479 range_ptr[1] = depth_min;
480 });
481
482 // Pass 1: iterate over rendering fragment array, fill-in range
484 block_keys.GetDevice(), frag_count * fragment_size * fragment_size,
485 [=] OPEN3D_DEVICE(int64_t workload_idx) {
486 int frag_idx = workload_idx / (fragment_size * fragment_size);
487 int local_idx = workload_idx % (fragment_size * fragment_size);
488 int dv = local_idx / fragment_size;
489 int du = local_idx % fragment_size;
490
491 float* frag_ptr =
492 frag_buffer_indexer.GetDataPtr<float>(frag_idx);
493 int v_min = static_cast<int>(frag_ptr[2]);
494 int u_min = static_cast<int>(frag_ptr[3]);
495 int v_max = static_cast<int>(frag_ptr[4]);
496 int u_max = static_cast<int>(frag_ptr[5]);
497
498 int v = v_min + dv;
499 int u = u_min + du;
500 if (v > v_max || u > u_max) return;
501
502 float z_min = frag_ptr[0];
503 float z_max = frag_ptr[1];
504 float* range_ptr = range_map_indexer.GetDataPtr<float>(u, v);
505#if defined(__CUDACC__)
506 atomicMinf(&(range_ptr[0]), z_min);
507 atomicMaxf(&(range_ptr[1]), z_max);
508#elif defined(SYCL_LANGUAGE_VERSION)
509 sycl::atomic_ref<float, sycl::memory_order::acq_rel,
510 sycl::memory_scope::device,
511 sycl::access::address_space::global_space>(
512 range_ptr[0])
513 .fetch_min(z_min);
514 sycl::atomic_ref<float, sycl::memory_order::acq_rel,
515 sycl::memory_scope::device,
516 sycl::access::address_space::global_space>(
517 range_ptr[1])
518 .fetch_max(z_max);
519#else
520#pragma omp critical(EstimateRangeCPU)
521 {
522 range_ptr[0] = min(z_min, range_ptr[0]);
523 range_ptr[1] = max(z_max, range_ptr[1]);
524 }
525#endif
526 });
527
528#if defined(__CUDACC__)
530#endif
531
532 if (needed_frag_count != frag_count) {
533 utility::LogInfo("Reallocating {} fragments for EstimateRange (was {})",
534 needed_frag_count, frag_count);
535
536 fragment_buffer = core::Tensor({needed_frag_count, 6}, core::Float32,
537 block_keys.GetDevice());
538 }
539}
540
546
548 return (xin == x && yin == y && zin == z) ? block_idx : -1;
549 }
550
551 inline void OPEN3D_DEVICE Update(index_t xin,
552 index_t yin,
553 index_t zin,
554 index_t block_idx_in) {
555 x = xin;
556 y = yin;
557 z = zin;
558 block_idx = block_idx_in;
559 }
560};
561
562template <typename tsdf_t, typename weight_t, typename color_t>
563#if defined(__CUDACC__)
564void RayCastCUDA
565#elif defined(SYCL_LANGUAGE_VERSION)
566void RayCastSYCL
567#else
569#endif
570 (std::shared_ptr<core::HashMap>& hashmap,
571 const TensorMap& block_value_map,
572 const core::Tensor& range,
573 TensorMap& renderings_map,
574 const core::Tensor& intrinsic,
575 const core::Tensor& extrinsics,
576 index_t h,
577 index_t w,
578 index_t block_resolution,
579 float voxel_size,
580 float depth_scale,
581 float depth_min,
582 float depth_max,
583 float weight_threshold,
584 float trunc_voxel_multiplier,
585 int range_map_down_factor) {
589
590 auto device_hashmap = hashmap->GetDeviceHashBackend();
591#if defined(__CUDACC__)
592 auto cuda_hashmap =
593 std::dynamic_pointer_cast<core::StdGPUHashBackend<Key, Hash, Eq>>(
594 device_hashmap);
595 if (cuda_hashmap == nullptr) {
596 utility::LogError(
597 "Unsupported backend: CUDA raycasting only supports STDGPU.");
598 }
599 auto hashmap_impl = cuda_hashmap->GetImpl();
600#elif defined(SYCL_LANGUAGE_VERSION)
601 auto sycl_hashmap =
602 std::dynamic_pointer_cast<core::SYCLHashBackend<Key, Hash, Eq>>(
603 device_hashmap);
604 if (sycl_hashmap == nullptr) {
605 utility::LogError(
606 "Unsupported backend: SYCL raycasting requires the SYCL "
607 "hash backend.");
608 }
609 auto sycl_hash_lookup = sycl_hashmap->GetDeviceLookup();
610#else
611 auto cpu_hashmap =
612 std::dynamic_pointer_cast<core::TBBHashBackend<Key, Hash, Eq>>(
613 device_hashmap);
614 if (cpu_hashmap == nullptr) {
615 utility::LogError(
616 "Unsupported backend: CPU raycasting only supports TBB.");
617 }
618 auto hashmap_impl = *cpu_hashmap->GetImpl();
619#endif
620
621 core::Device device = hashmap->GetDevice();
622
623 ArrayIndexer range_indexer(range, 2);
624
625 // Geometry
626 ArrayIndexer depth_indexer;
627 ArrayIndexer vertex_indexer;
628 ArrayIndexer normal_indexer;
629
630 // Diff rendering
631 ArrayIndexer index_indexer;
632 ArrayIndexer mask_indexer;
633 ArrayIndexer interp_ratio_indexer;
634 ArrayIndexer interp_ratio_dx_indexer;
635 ArrayIndexer interp_ratio_dy_indexer;
636 ArrayIndexer interp_ratio_dz_indexer;
637
638 // Color
639 ArrayIndexer color_indexer;
640
641 if (!block_value_map.Contains("tsdf") ||
642 !block_value_map.Contains("weight")) {
643 utility::LogError(
644 "TSDF and/or weight not allocated in blocks, please implement "
645 "customized integration.");
646 }
647 const tsdf_t* tsdf_base_ptr =
648 block_value_map.at("tsdf").GetDataPtr<tsdf_t>();
649 const weight_t* weight_base_ptr =
650 block_value_map.at("weight").GetDataPtr<weight_t>();
651
652 // Geometry
653 if (renderings_map.Contains("depth")) {
654 depth_indexer = ArrayIndexer(renderings_map.at("depth"), 2);
655 }
656 if (renderings_map.Contains("vertex")) {
657 vertex_indexer = ArrayIndexer(renderings_map.at("vertex"), 2);
658 }
659 if (renderings_map.Contains("normal")) {
660 normal_indexer = ArrayIndexer(renderings_map.at("normal"), 2);
661 }
662
663 // Diff rendering
664 if (renderings_map.Contains("index")) {
665 index_indexer = ArrayIndexer(renderings_map.at("index"), 2);
666 }
667 if (renderings_map.Contains("mask")) {
668 mask_indexer = ArrayIndexer(renderings_map.at("mask"), 2);
669 }
670 if (renderings_map.Contains("interp_ratio")) {
671 interp_ratio_indexer =
672 ArrayIndexer(renderings_map.at("interp_ratio"), 2);
673 }
674 if (renderings_map.Contains("interp_ratio_dx")) {
675 interp_ratio_dx_indexer =
676 ArrayIndexer(renderings_map.at("interp_ratio_dx"), 2);
677 }
678 if (renderings_map.Contains("interp_ratio_dy")) {
679 interp_ratio_dy_indexer =
680 ArrayIndexer(renderings_map.at("interp_ratio_dy"), 2);
681 }
682 if (renderings_map.Contains("interp_ratio_dz")) {
683 interp_ratio_dz_indexer =
684 ArrayIndexer(renderings_map.at("interp_ratio_dz"), 2);
685 }
686
687 // Color
688 bool render_color = false;
689 if (block_value_map.Contains("color") && renderings_map.Contains("color")) {
690 render_color = true;
691 color_indexer = ArrayIndexer(renderings_map.at("color"), 2);
692 }
693 const color_t* color_base_ptr =
694 render_color ? block_value_map.at("color").GetDataPtr<color_t>()
695 : nullptr;
696
697 bool visit_neighbors = render_color || normal_indexer.GetDataPtr() ||
698 mask_indexer.GetDataPtr() ||
699 index_indexer.GetDataPtr() ||
700 interp_ratio_indexer.GetDataPtr() ||
701 interp_ratio_dx_indexer.GetDataPtr() ||
702 interp_ratio_dy_indexer.GetDataPtr() ||
703 interp_ratio_dz_indexer.GetDataPtr();
704
705 TransformIndexer c2w_transform_indexer(
706 intrinsic, t::geometry::InverseTransformation(extrinsics));
707 TransformIndexer w2c_transform_indexer(intrinsic, extrinsics);
708
709 index_t rows = h;
710 index_t cols = w;
711 index_t n = rows * cols;
712
713 float block_size = voxel_size * block_resolution;
714 index_t resolution2 = block_resolution * block_resolution;
715 index_t resolution3 = resolution2 * block_resolution;
716
717#ifndef __CUDACC__
718 using std::max;
719 using std::sqrt;
720#elif defined(SYCL_LANGUAGE_VERSION)
721 using sycl::max;
722 using sycl::sqrt;
723#endif
724
725 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t workload_idx) {
726 auto GetLinearIdxAtP = [&] OPEN3D_DEVICE(
727 index_t x_b, index_t y_b, index_t z_b,
728 index_t x_v, index_t y_v, index_t z_v,
729 core::buf_index_t block_buf_idx,
730 MiniVecCache & cache) -> index_t {
731 index_t x_vn = (x_v + block_resolution) % block_resolution;
732 index_t y_vn = (y_v + block_resolution) % block_resolution;
733 index_t z_vn = (z_v + block_resolution) % block_resolution;
734
735 index_t dx_b = Sign(x_v - x_vn);
736 index_t dy_b = Sign(y_v - y_vn);
737 index_t dz_b = Sign(z_v - z_vn);
738
739 if (dx_b == 0 && dy_b == 0 && dz_b == 0) {
740 return block_buf_idx * resolution3 + z_v * resolution2 +
741 y_v * block_resolution + x_v;
742 } else {
743 Key key(x_b + dx_b, y_b + dy_b, z_b + dz_b);
744
745 index_t block_buf_idx = cache.Check(key[0], key[1], key[2]);
746 if (block_buf_idx < 0) {
747#if defined(__CUDACC__)
748 auto iter = hashmap_impl.find(key);
749 if (iter == hashmap_impl.end()) return -1;
750 block_buf_idx = iter->second;
751#elif defined(SYCL_LANGUAGE_VERSION)
752 core::buf_index_t bi = sycl_hash_lookup.Find(key);
753 if (bi == static_cast<core::buf_index_t>(-1)) return -1;
754 block_buf_idx = static_cast<index_t>(bi);
755#else
756 auto iter = hashmap_impl.find(key);
757 if (iter == hashmap_impl.end()) return -1;
758 block_buf_idx = iter->second;
759#endif
760 cache.Update(key[0], key[1], key[2], block_buf_idx);
761 }
762
763 return block_buf_idx * resolution3 + z_vn * resolution2 +
764 y_vn * block_resolution + x_vn;
765 }
766 };
767
768 auto GetLinearIdxAtT = [&] OPEN3D_DEVICE(
769 float x_o, float y_o, float z_o,
770 float x_d, float y_d, float z_d, float t,
771 MiniVecCache& cache) -> index_t {
772 float x_g = x_o + t * x_d;
773 float y_g = y_o + t * y_d;
774 float z_g = z_o + t * z_d;
775
776 // MiniVec coordinate and look up
777 index_t x_b = static_cast<index_t>(floorf(x_g / block_size));
778 index_t y_b = static_cast<index_t>(floorf(y_g / block_size));
779 index_t z_b = static_cast<index_t>(floorf(z_g / block_size));
780
781 Key key(x_b, y_b, z_b);
782 index_t block_buf_idx = cache.Check(x_b, y_b, z_b);
783 if (block_buf_idx < 0) {
784#if defined(__CUDACC__)
785 auto iter = hashmap_impl.find(key);
786 if (iter == hashmap_impl.end()) return -1;
787 block_buf_idx = iter->second;
788#elif defined(SYCL_LANGUAGE_VERSION)
789 core::buf_index_t bi = sycl_hash_lookup.Find(key);
790 if (bi == static_cast<core::buf_index_t>(-1)) return -1;
791 block_buf_idx = static_cast<index_t>(bi);
792#else
793 auto iter = hashmap_impl.find(key);
794 if (iter == hashmap_impl.end()) return -1;
795 block_buf_idx = iter->second;
796#endif
797 cache.Update(x_b, y_b, z_b, block_buf_idx);
798 }
799
800 // Voxel coordinate and look up
801 index_t x_v = index_t((x_g - x_b * block_size) / voxel_size);
802 index_t y_v = index_t((y_g - y_b * block_size) / voxel_size);
803 index_t z_v = index_t((z_g - z_b * block_size) / voxel_size);
804
805 return block_buf_idx * resolution3 + z_v * resolution2 +
806 y_v * block_resolution + x_v;
807 };
808
809 index_t y = workload_idx / cols;
810 index_t x = workload_idx % cols;
811
812 const float* range = range_indexer.GetDataPtr<float>(
813 x / range_map_down_factor, y / range_map_down_factor);
814
815 float* depth_ptr = nullptr;
816 float* vertex_ptr = nullptr;
817 float* color_ptr = nullptr;
818 float* normal_ptr = nullptr;
819
820 int64_t* index_ptr = nullptr;
821 bool* mask_ptr = nullptr;
822 float* interp_ratio_ptr = nullptr;
823 float* interp_ratio_dx_ptr = nullptr;
824 float* interp_ratio_dy_ptr = nullptr;
825 float* interp_ratio_dz_ptr = nullptr;
826
827 if (vertex_indexer.GetDataPtr()) {
828 vertex_ptr = vertex_indexer.GetDataPtr<float>(x, y);
829 vertex_ptr[0] = 0;
830 vertex_ptr[1] = 0;
831 vertex_ptr[2] = 0;
832 }
833 if (depth_indexer.GetDataPtr()) {
834 depth_ptr = depth_indexer.GetDataPtr<float>(x, y);
835 depth_ptr[0] = 0;
836 }
837 if (normal_indexer.GetDataPtr()) {
838 normal_ptr = normal_indexer.GetDataPtr<float>(x, y);
839 normal_ptr[0] = 0;
840 normal_ptr[1] = 0;
841 normal_ptr[2] = 0;
842 }
843
844 if (mask_indexer.GetDataPtr()) {
845 mask_ptr = mask_indexer.GetDataPtr<bool>(x, y);
846#ifdef __CUDACC__
847#pragma unroll
848#endif
849 for (int i = 0; i < 8; ++i) {
850 mask_ptr[i] = false;
851 }
852 }
853 if (index_indexer.GetDataPtr()) {
854 index_ptr = index_indexer.GetDataPtr<int64_t>(x, y);
855#ifdef __CUDACC__
856#pragma unroll
857#endif
858 for (int i = 0; i < 8; ++i) {
859 index_ptr[i] = 0;
860 }
861 }
862 if (interp_ratio_indexer.GetDataPtr()) {
863 interp_ratio_ptr = interp_ratio_indexer.GetDataPtr<float>(x, y);
864#ifdef __CUDACC__
865#pragma unroll
866#endif
867 for (int i = 0; i < 8; ++i) {
868 interp_ratio_ptr[i] = 0;
869 }
870 }
871 if (interp_ratio_dx_indexer.GetDataPtr()) {
872 interp_ratio_dx_ptr =
873 interp_ratio_dx_indexer.GetDataPtr<float>(x, y);
874#ifdef __CUDACC__
875#pragma unroll
876#endif
877 for (int i = 0; i < 8; ++i) {
878 interp_ratio_dx_ptr[i] = 0;
879 }
880 }
881 if (interp_ratio_dy_indexer.GetDataPtr()) {
882 interp_ratio_dy_ptr =
883 interp_ratio_dy_indexer.GetDataPtr<float>(x, y);
884#ifdef __CUDACC__
885#pragma unroll
886#endif
887 for (int i = 0; i < 8; ++i) {
888 interp_ratio_dy_ptr[i] = 0;
889 }
890 }
891 if (interp_ratio_dz_indexer.GetDataPtr()) {
892 interp_ratio_dz_ptr =
893 interp_ratio_dz_indexer.GetDataPtr<float>(x, y);
894#ifdef __CUDACC__
895#pragma unroll
896#endif
897 for (int i = 0; i < 8; ++i) {
898 interp_ratio_dz_ptr[i] = 0;
899 }
900 }
901
902 if (color_indexer.GetDataPtr()) {
903 color_ptr = color_indexer.GetDataPtr<float>(x, y);
904 color_ptr[0] = 0;
905 color_ptr[1] = 0;
906 color_ptr[2] = 0;
907 }
908
909 float t = range[0];
910 const float t_max = range[1];
911 if (t >= t_max) return;
912
913 // Coordinates in camera and global
914 float x_c = 0, y_c = 0, z_c = 0;
915 float x_g = 0, y_g = 0, z_g = 0;
916 float x_o = 0, y_o = 0, z_o = 0;
917
918 // Iterative ray intersection check
919 float t_prev = t;
920
921 float tsdf_prev = -1.0f;
922 float tsdf = 1.0;
923 float sdf_trunc = voxel_size * trunc_voxel_multiplier;
924 float w = 0.0;
925
926 // Camera origin
927 c2w_transform_indexer.RigidTransform(0, 0, 0, &x_o, &y_o, &z_o);
928
929 // Direction
930 c2w_transform_indexer.Unproject(static_cast<float>(x),
931 static_cast<float>(y), 1.0f, &x_c, &y_c,
932 &z_c);
933 c2w_transform_indexer.RigidTransform(x_c, y_c, z_c, &x_g, &y_g, &z_g);
934 float x_d = (x_g - x_o);
935 float y_d = (y_g - y_o);
936 float z_d = (z_g - z_o);
937
938 MiniVecCache cache{0, 0, 0, -1};
939 bool surface_found = false;
940 while (t < t_max) {
941 index_t linear_idx =
942 GetLinearIdxAtT(x_o, y_o, z_o, x_d, y_d, z_d, t, cache);
943
944 if (linear_idx < 0) {
945 t_prev = t;
946 t += block_size;
947 } else {
948 tsdf_prev = tsdf;
949 tsdf = tsdf_base_ptr[linear_idx];
950 w = weight_base_ptr[linear_idx];
951 if (tsdf_prev > 0 && w >= weight_threshold && tsdf <= 0) {
952 surface_found = true;
953 break;
954 }
955 t_prev = t;
956 float delta = tsdf * sdf_trunc;
957 t += delta < voxel_size ? voxel_size : delta;
958 }
959 }
960
961 if (surface_found) {
962 float t_intersect =
963 (t * tsdf_prev - t_prev * tsdf) / (tsdf_prev - tsdf);
964 x_g = x_o + t_intersect * x_d;
965 y_g = y_o + t_intersect * y_d;
966 z_g = z_o + t_intersect * z_d;
967
968 // Trivial vertex assignment
969 if (depth_ptr) {
970 *depth_ptr = t_intersect * depth_scale;
971 }
972 if (vertex_ptr) {
973 w2c_transform_indexer.RigidTransform(
974 x_g, y_g, z_g, vertex_ptr + 0, vertex_ptr + 1,
975 vertex_ptr + 2);
976 }
977 if (!visit_neighbors) return;
978
979 // Trilinear interpolation
980 // TODO(wei): simplify the flow by splitting the
981 // functions given what is enabled
982 index_t x_b = static_cast<index_t>(floorf(x_g / block_size));
983 index_t y_b = static_cast<index_t>(floorf(y_g / block_size));
984 index_t z_b = static_cast<index_t>(floorf(z_g / block_size));
985 float x_v = (x_g - float(x_b) * block_size) / voxel_size;
986 float y_v = (y_g - float(y_b) * block_size) / voxel_size;
987 float z_v = (z_g - float(z_b) * block_size) / voxel_size;
988
989 Key key(x_b, y_b, z_b);
990
991 index_t block_buf_idx = cache.Check(x_b, y_b, z_b);
992 if (block_buf_idx < 0) {
993#if defined(__CUDACC__)
994 auto iter = hashmap_impl.find(key);
995 if (iter == hashmap_impl.end()) return;
996 block_buf_idx = iter->second;
997#elif defined(SYCL_LANGUAGE_VERSION)
998 core::buf_index_t bi = sycl_hash_lookup.Find(key);
999 if (bi == static_cast<core::buf_index_t>(-1)) return;
1000 block_buf_idx = static_cast<index_t>(bi);
1001#else
1002 auto iter = hashmap_impl.find(key);
1003 if (iter == hashmap_impl.end()) return;
1004 block_buf_idx = iter->second;
1005#endif
1006 cache.Update(x_b, y_b, z_b, block_buf_idx);
1007 }
1008
1009 index_t x_v_floor = static_cast<index_t>(floorf(x_v));
1010 index_t y_v_floor = static_cast<index_t>(floorf(y_v));
1011 index_t z_v_floor = static_cast<index_t>(floorf(z_v));
1012
1013 float ratio_x = x_v - float(x_v_floor);
1014 float ratio_y = y_v - float(y_v_floor);
1015 float ratio_z = z_v - float(z_v_floor);
1016
1017 float sum_r = 0.0;
1018 for (index_t k = 0; k < 8; ++k) {
1019 index_t dx_v = (k & 1) > 0 ? 1 : 0;
1020 index_t dy_v = (k & 2) > 0 ? 1 : 0;
1021 index_t dz_v = (k & 4) > 0 ? 1 : 0;
1022
1023 index_t linear_idx_k = GetLinearIdxAtP(
1024 x_b, y_b, z_b, x_v_floor + dx_v, y_v_floor + dy_v,
1025 z_v_floor + dz_v, block_buf_idx, cache);
1026
1027 if (linear_idx_k >= 0 && weight_base_ptr[linear_idx_k] > 0) {
1028 float rx = dx_v * (ratio_x) + (1 - dx_v) * (1 - ratio_x);
1029 float ry = dy_v * (ratio_y) + (1 - dy_v) * (1 - ratio_y);
1030 float rz = dz_v * (ratio_z) + (1 - dz_v) * (1 - ratio_z);
1031 float r = rx * ry * rz;
1032
1033 if (interp_ratio_ptr) {
1034 interp_ratio_ptr[k] = r;
1035 }
1036 if (mask_ptr) {
1037 mask_ptr[k] = true;
1038 }
1039 if (index_ptr) {
1040 index_ptr[k] = linear_idx_k;
1041 }
1042
1043 float tsdf_k = tsdf_base_ptr[linear_idx_k];
1044 float interp_ratio_dx = ry * rz * (2 * dx_v - 1);
1045 float interp_ratio_dy = rx * rz * (2 * dy_v - 1);
1046 float interp_ratio_dz = rx * ry * (2 * dz_v - 1);
1047
1048 if (interp_ratio_dx_ptr) {
1049 interp_ratio_dx_ptr[k] = interp_ratio_dx;
1050 }
1051 if (interp_ratio_dy_ptr) {
1052 interp_ratio_dy_ptr[k] = interp_ratio_dy;
1053 }
1054 if (interp_ratio_dz_ptr) {
1055 interp_ratio_dz_ptr[k] = interp_ratio_dz;
1056 }
1057
1058 if (normal_ptr) {
1059 normal_ptr[0] += interp_ratio_dx * tsdf_k;
1060 normal_ptr[1] += interp_ratio_dy * tsdf_k;
1061 normal_ptr[2] += interp_ratio_dz * tsdf_k;
1062 }
1063
1064 if (color_ptr) {
1065 index_t color_linear_idx = linear_idx_k * 3;
1066 color_ptr[0] +=
1067 r * color_base_ptr[color_linear_idx + 0];
1068 color_ptr[1] +=
1069 r * color_base_ptr[color_linear_idx + 1];
1070 color_ptr[2] +=
1071 r * color_base_ptr[color_linear_idx + 2];
1072 }
1073
1074 sum_r += r;
1075 }
1076 } // loop over 8 neighbors
1077
1078 if (sum_r > 0) {
1079 sum_r *= 255.0;
1080 if (color_ptr) {
1081 color_ptr[0] /= sum_r;
1082 color_ptr[1] /= sum_r;
1083 color_ptr[2] /= sum_r;
1084 }
1085
1086 if (normal_ptr) {
1087 constexpr float EPSILON = 1e-5f;
1088 float norm = sqrt(normal_ptr[0] * normal_ptr[0] +
1089 normal_ptr[1] * normal_ptr[1] +
1090 normal_ptr[2] * normal_ptr[2]);
1091 norm = max(norm, EPSILON);
1092 w2c_transform_indexer.Rotate(
1093 -normal_ptr[0] / norm, -normal_ptr[1] / norm,
1094 -normal_ptr[2] / norm, normal_ptr + 0,
1095 normal_ptr + 1, normal_ptr + 2);
1096 }
1097 }
1098 } // surface-found
1099 });
1100
1101#if defined(__CUDACC__)
1103#endif
1104}
1105
1106template <typename tsdf_t, typename weight_t, typename color_t>
1107#if defined(__CUDACC__)
1108void ExtractPointCloudCUDA
1109#elif defined(SYCL_LANGUAGE_VERSION)
1110void ExtractPointCloudSYCL
1111#else
1113#endif
1114 (const core::Tensor& indices,
1115 const core::Tensor& nb_indices,
1116 const core::Tensor& nb_masks,
1117 const core::Tensor& block_keys,
1118 const TensorMap& block_value_map,
1121 core::Tensor& colors,
1122 index_t resolution,
1123 float voxel_size,
1124 float weight_threshold,
1125 int& valid_size) {
1126 core::Device device = block_keys.GetDevice();
1127
1128 // Parameters
1129 index_t resolution2 = resolution * resolution;
1130 index_t resolution3 = resolution2 * resolution;
1131
1132 // Shape / transform indexers, no data involved
1133 ArrayIndexer voxel_indexer({resolution, resolution, resolution});
1134
1135 // Real data indexer
1136 ArrayIndexer block_keys_indexer(block_keys, 1);
1137 ArrayIndexer nb_block_masks_indexer(nb_masks, 2);
1138 ArrayIndexer nb_block_indices_indexer(nb_indices, 2);
1139
1140 // Plain arrays that does not require indexers
1141 const index_t* indices_ptr = indices.GetDataPtr<index_t>();
1142
1143 if (!block_value_map.Contains("tsdf") ||
1144 !block_value_map.Contains("weight")) {
1145 utility::LogError(
1146 "TSDF and/or weight not allocated in blocks, please implement "
1147 "customized integration.");
1148 }
1149 const tsdf_t* tsdf_base_ptr =
1150 block_value_map.at("tsdf").GetDataPtr<tsdf_t>();
1151 const weight_t* weight_base_ptr =
1152 block_value_map.at("weight").GetDataPtr<weight_t>();
1153 const color_t* color_base_ptr = nullptr;
1154 if (block_value_map.Contains("color")) {
1155 color_base_ptr = block_value_map.at("color").GetDataPtr<color_t>();
1156 }
1157
1158 index_t n_blocks = indices.GetLength();
1159 index_t n = n_blocks * resolution3;
1160
1161 // Output
1162#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1163 core::Tensor count(std::vector<index_t>{0}, {1}, core::Int32,
1164 block_keys.GetDevice());
1165 index_t* count_ptr = count.GetDataPtr<index_t>();
1166#else
1167 std::atomic<index_t> count_atomic(0);
1168 std::atomic<index_t>* count_ptr = &count_atomic;
1169#endif
1170
1171 if (valid_size < 0) {
1172 utility::LogDebug(
1173 "No estimated max point cloud size provided, using a 2-pass "
1174 "estimation. Surface extraction could be slow.");
1175 // This pass determines valid number of points.
1176
1177 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t workload_idx) {
1178 auto GetLinearIdx = [&] OPEN3D_DEVICE(
1179 index_t xo, index_t yo, index_t zo,
1180 index_t curr_block_idx) -> index_t {
1181 return DeviceGetLinearIdx(xo, yo, zo, curr_block_idx,
1182 resolution, nb_block_masks_indexer,
1183 nb_block_indices_indexer);
1184 };
1185
1186 // Natural index (0, N) -> (block_idx,
1187 // voxel_idx)
1188 index_t workload_block_idx = workload_idx / resolution3;
1189 index_t block_idx = indices_ptr[workload_block_idx];
1190 index_t voxel_idx = workload_idx % resolution3;
1191
1192 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1193 index_t xv, yv, zv;
1194 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1195
1196 index_t linear_idx = block_idx * resolution3 + voxel_idx;
1197 float tsdf_o = tsdf_base_ptr[linear_idx];
1198 float weight_o = weight_base_ptr[linear_idx];
1199 if (weight_o <= weight_threshold) return;
1200
1201 // Enumerate x-y-z directions
1202 for (index_t i = 0; i < 3; ++i) {
1203 index_t linear_idx_i =
1204 GetLinearIdx(xv + (i == 0), yv + (i == 1),
1205 zv + (i == 2), workload_block_idx);
1206 if (linear_idx_i < 0) continue;
1207
1208 float tsdf_i = tsdf_base_ptr[linear_idx_i];
1209 float weight_i = weight_base_ptr[linear_idx_i];
1210 if (weight_i > weight_threshold && tsdf_i * tsdf_o < 0) {
1211 OPEN3D_ATOMIC_ADD(count_ptr, 1);
1212 }
1213 }
1214 });
1215
1216#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1217 valid_size = count[0].Item<index_t>();
1218 count[0] = 0;
1219#else
1220 valid_size = (*count_ptr).load();
1221 (*count_ptr) = 0;
1222#endif
1223 }
1224
1225 if (points.GetLength() == 0) {
1226 points = core::Tensor({valid_size, 3}, core::Float32, device);
1227 }
1228 ArrayIndexer point_indexer(points, 1);
1229
1230 // Normals
1231 ArrayIndexer normal_indexer;
1232 normals = core::Tensor({valid_size, 3}, core::Float32, device);
1233 normal_indexer = ArrayIndexer(normals, 1);
1234
1235 // This pass extracts exact surface points.
1236
1237 // Colors
1238 ArrayIndexer color_indexer;
1239 if (color_base_ptr) {
1240 colors = core::Tensor({valid_size, 3}, core::Float32, device);
1241 color_indexer = ArrayIndexer(colors, 1);
1242 }
1243
1244 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t workload_idx) {
1245 auto GetLinearIdx = [&] OPEN3D_DEVICE(
1246 index_t xo, index_t yo, index_t zo,
1247 index_t curr_block_idx) -> index_t {
1248 return DeviceGetLinearIdx(xo, yo, zo, curr_block_idx, resolution,
1249 nb_block_masks_indexer,
1250 nb_block_indices_indexer);
1251 };
1252
1253 auto GetNormal = [&] OPEN3D_DEVICE(index_t xo, index_t yo, index_t zo,
1254 index_t curr_block_idx, float* n) {
1255 return DeviceGetNormal<tsdf_t>(
1256 tsdf_base_ptr, xo, yo, zo, curr_block_idx, n, resolution,
1257 nb_block_masks_indexer, nb_block_indices_indexer);
1258 };
1259
1260 // Natural index (0, N) -> (block_idx, voxel_idx)
1261 index_t workload_block_idx = workload_idx / resolution3;
1262 index_t block_idx = indices_ptr[workload_block_idx];
1263 index_t voxel_idx = workload_idx % resolution3;
1264
1266 // block_idx -> (x_block, y_block, z_block)
1267 index_t* block_key_ptr =
1268 block_keys_indexer.GetDataPtr<index_t>(block_idx);
1269 index_t xb = block_key_ptr[0];
1270 index_t yb = block_key_ptr[1];
1271 index_t zb = block_key_ptr[2];
1272
1273 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1274 index_t xv, yv, zv;
1275 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1276
1277 index_t linear_idx = block_idx * resolution3 + voxel_idx;
1278 float tsdf_o = tsdf_base_ptr[linear_idx];
1279 float weight_o = weight_base_ptr[linear_idx];
1280 if (weight_o <= weight_threshold) return;
1281
1282 float no[3] = {0}, ne[3] = {0};
1283
1284 // Get normal at origin
1285 GetNormal(xv, yv, zv, workload_block_idx, no);
1286
1287 index_t x = xb * resolution + xv;
1288 index_t y = yb * resolution + yv;
1289 index_t z = zb * resolution + zv;
1290
1291 // Enumerate x-y-z axis
1292 for (index_t i = 0; i < 3; ++i) {
1293 index_t linear_idx_i =
1294 GetLinearIdx(xv + (i == 0), yv + (i == 1), zv + (i == 2),
1295 workload_block_idx);
1296 if (linear_idx_i < 0) continue;
1297
1298 float tsdf_i = tsdf_base_ptr[linear_idx_i];
1299 float weight_i = weight_base_ptr[linear_idx_i];
1300 if (weight_i > weight_threshold && tsdf_i * tsdf_o < 0) {
1301 float ratio = (0 - tsdf_o) / (tsdf_i - tsdf_o);
1302
1303 index_t idx = OPEN3D_ATOMIC_ADD(count_ptr, 1);
1304 if (idx >= valid_size) {
1305#if defined(__CUDACC__)
1306 printf("Point cloud size larger than "
1307 "estimated, please increase the "
1308 "estimation!\n");
1309#endif
1310 return;
1311 }
1312
1313 float* point_ptr = point_indexer.GetDataPtr<float>(idx);
1314 point_ptr[0] = voxel_size * (x + ratio * int(i == 0));
1315 point_ptr[1] = voxel_size * (y + ratio * int(i == 1));
1316 point_ptr[2] = voxel_size * (z + ratio * int(i == 2));
1317
1318 // Get normal at edge and interpolate
1319 float* normal_ptr = normal_indexer.GetDataPtr<float>(idx);
1320 GetNormal(xv + (i == 0), yv + (i == 1), zv + (i == 2),
1321 workload_block_idx, ne);
1322 float nx = (1 - ratio) * no[0] + ratio * ne[0];
1323 float ny = (1 - ratio) * no[1] + ratio * ne[1];
1324 float nz = (1 - ratio) * no[2] + ratio * ne[2];
1325 float norm = static_cast<float>(
1326 sqrt(nx * nx + ny * ny + nz * nz) + 1e-5);
1327 normal_ptr[0] = nx / norm;
1328 normal_ptr[1] = ny / norm;
1329 normal_ptr[2] = nz / norm;
1330
1331 if (color_base_ptr) {
1332 float* color_ptr = color_indexer.GetDataPtr<float>(idx);
1333 const color_t* color_o_ptr =
1334 color_base_ptr + 3 * linear_idx;
1335 float r_o = color_o_ptr[0];
1336 float g_o = color_o_ptr[1];
1337 float b_o = color_o_ptr[2];
1338
1339 const color_t* color_i_ptr =
1340 color_base_ptr + 3 * linear_idx_i;
1341 float r_i = color_i_ptr[0];
1342 float g_i = color_i_ptr[1];
1343 float b_i = color_i_ptr[2];
1344
1345 color_ptr[0] = ((1 - ratio) * r_o + ratio * r_i) / 255.0f;
1346 color_ptr[1] = ((1 - ratio) * g_o + ratio * g_i) / 255.0f;
1347 color_ptr[2] = ((1 - ratio) * b_o + ratio * b_i) / 255.0f;
1348 }
1349 }
1350 }
1351 });
1352
1353#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1354 index_t total_count = count.Item<index_t>();
1355#else
1356 index_t total_count = (*count_ptr).load();
1357#endif
1358
1359 utility::LogDebug("{} vertices extracted", total_count);
1360 valid_size = total_count;
1361
1362#if defined(BUILD_CUDA_MODULE) && defined(__CUDACC__)
1364#endif
1365}
1366
1367template <typename tsdf_t, typename weight_t, typename color_t>
1368#if defined(__CUDACC__)
1369void ExtractTriangleMeshCUDA
1370#elif defined(SYCL_LANGUAGE_VERSION)
1371void ExtractTriangleMeshSYCL
1372#else
1374#endif
1375 (const core::Tensor& block_indices,
1376 const core::Tensor& inv_block_indices,
1377 const core::Tensor& nb_block_indices,
1378 const core::Tensor& nb_block_masks,
1379 const core::Tensor& block_keys,
1380 const TensorMap& block_value_map,
1381 core::Tensor& vertices,
1382 core::Tensor& triangles,
1383 core::Tensor& vertex_normals,
1384 core::Tensor& vertex_colors,
1385 index_t block_resolution,
1386 float voxel_size,
1387 float weight_threshold,
1388 index_t& vertex_count) {
1389 core::Device device = block_indices.GetDevice();
1390
1391 index_t resolution = block_resolution;
1392 index_t resolution3 = resolution * resolution * resolution;
1393
1394 // Shape / transform indexers, no data involved
1395 ArrayIndexer voxel_indexer({resolution, resolution, resolution});
1396 index_t n_blocks = static_cast<index_t>(block_indices.GetLength());
1397
1398 // TODO(wei): profile performance by replacing the table to a hashmap.
1399 // Voxel-wise mesh info. 4 channels correspond to:
1400 // 3 edges' corresponding vertex index + 1 table index.
1401 core::Tensor mesh_structure;
1402 try {
1403 mesh_structure = core::Tensor::Zeros(
1404 {n_blocks, resolution, resolution, resolution, 4}, core::Int32,
1405 device);
1406 } catch (const std::runtime_error&) {
1407 utility::LogError(
1408 "Unable to allocate assistance mesh structure for Marching "
1409 "Cubes with {} active voxel blocks. Please consider using a "
1410 "larger voxel size (currently {}) for TSDF integration, or "
1411 "using tsdf_volume.cpu() to perform mesh extraction on CPU.",
1412 n_blocks, voxel_size);
1413 }
1414
1415 // Real data indexer
1416 ArrayIndexer mesh_structure_indexer(mesh_structure, 4);
1417 ArrayIndexer nb_block_masks_indexer(nb_block_masks, 2);
1418 ArrayIndexer nb_block_indices_indexer(nb_block_indices, 2);
1419
1420 // Plain arrays that does not require indexers
1421 const index_t* indices_ptr = block_indices.GetDataPtr<index_t>();
1422 const index_t* inv_indices_ptr = inv_block_indices.GetDataPtr<index_t>();
1423
1424 if (!block_value_map.Contains("tsdf") ||
1425 !block_value_map.Contains("weight")) {
1426 utility::LogError(
1427 "TSDF and/or weight not allocated in blocks, please implement "
1428 "customized integration.");
1429 }
1430 const tsdf_t* tsdf_base_ptr =
1431 block_value_map.at("tsdf").GetDataPtr<tsdf_t>();
1432 const weight_t* weight_base_ptr =
1433 block_value_map.at("weight").GetDataPtr<weight_t>();
1434 const color_t* color_base_ptr = nullptr;
1435 if (block_value_map.Contains("color")) {
1436 color_base_ptr = block_value_map.at("color").GetDataPtr<color_t>();
1437 }
1438
1439 index_t n = n_blocks * resolution3;
1440 // Pass 0: analyze mesh structure, set up one-on-one correspondences
1441 // from edges to vertices.
1442
1443 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t widx) {
1444 auto GetLinearIdx = [&] OPEN3D_DEVICE(
1445 index_t xo, index_t yo, index_t zo,
1446 index_t curr_block_idx) -> index_t {
1447 return DeviceGetLinearIdx(xo, yo, zo, curr_block_idx,
1448 static_cast<index_t>(resolution),
1449 nb_block_masks_indexer,
1450 nb_block_indices_indexer);
1451 };
1452
1453 // Natural index (0, N) -> (block_idx, voxel_idx)
1454 index_t workload_block_idx = widx / resolution3;
1455 index_t voxel_idx = widx % resolution3;
1456
1457 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1458 index_t xv, yv, zv;
1459 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1460
1461 // Check per-vertex sign in the cube to determine cube
1462 // type
1463 index_t table_idx = 0;
1464 for (index_t i = 0; i < 8; ++i) {
1465 index_t linear_idx_i =
1466 GetLinearIdx(xv + vtx_shifts[i][0], yv + vtx_shifts[i][1],
1467 zv + vtx_shifts[i][2], workload_block_idx);
1468 if (linear_idx_i < 0) return;
1469
1470 float tsdf_i = tsdf_base_ptr[linear_idx_i];
1471 float weight_i = weight_base_ptr[linear_idx_i];
1472 if (weight_i <= weight_threshold) return;
1473
1474 table_idx |= ((tsdf_i < 0) ? (1 << i) : 0);
1475 }
1476
1477 index_t* mesh_struct_ptr = mesh_structure_indexer.GetDataPtr<index_t>(
1478 xv, yv, zv, workload_block_idx);
1479 mesh_struct_ptr[3] = table_idx;
1480
1481 if (table_idx == 0 || table_idx == 255) return;
1482
1483 // Check per-edge sign determine the cube type
1484 index_t edges_with_vertices = edge_table[table_idx];
1485 for (index_t i = 0; i < 12; ++i) {
1486 if (edges_with_vertices & (1 << i)) {
1487 index_t xv_i = xv + edge_shifts[i][0];
1488 index_t yv_i = yv + edge_shifts[i][1];
1489 index_t zv_i = zv + edge_shifts[i][2];
1490 index_t edge_i = edge_shifts[i][3];
1491
1492 index_t dxb = xv_i / resolution;
1493 index_t dyb = yv_i / resolution;
1494 index_t dzb = zv_i / resolution;
1495
1496 index_t nb_idx = (dxb + 1) + (dyb + 1) * 3 + (dzb + 1) * 9;
1497
1498 index_t block_idx_i =
1499 *nb_block_indices_indexer.GetDataPtr<index_t>(
1500 workload_block_idx, nb_idx);
1501 index_t* mesh_ptr_i =
1502 mesh_structure_indexer.GetDataPtr<index_t>(
1503 xv_i - dxb * resolution,
1504 yv_i - dyb * resolution,
1505 zv_i - dzb * resolution,
1506 inv_indices_ptr[block_idx_i]);
1507
1508 // Non-atomic write, but we are safe
1509 mesh_ptr_i[edge_i] = -1;
1510 }
1511 }
1512 });
1513
1514 // Pass 1: determine valid number of vertices (if not preset)
1515#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1516 core::Tensor count(std::vector<index_t>{0}, {}, core::Int32, device);
1517
1518 index_t* count_ptr = count.GetDataPtr<index_t>();
1519#else
1520 std::atomic<index_t> count_atomic(0);
1521 std::atomic<index_t>* count_ptr = &count_atomic;
1522#endif
1523
1524 if (vertex_count < 0) {
1525 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t widx) {
1526 // Natural index (0, N) -> (block_idx, voxel_idx)
1527 index_t workload_block_idx = widx / resolution3;
1528 index_t voxel_idx = widx % resolution3;
1529
1530 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1531 index_t xv, yv, zv;
1532 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1533
1534 // Obtain voxel's mesh struct ptr
1535 index_t* mesh_struct_ptr =
1536 mesh_structure_indexer.GetDataPtr<index_t>(
1537 xv, yv, zv, workload_block_idx);
1538
1539 // Early quit -- no allocated vertex to compute
1540 if (mesh_struct_ptr[0] != -1 && mesh_struct_ptr[1] != -1 &&
1541 mesh_struct_ptr[2] != -1) {
1542 return;
1543 }
1544
1545 // Enumerate 3 edges in the voxel
1546 for (index_t e = 0; e < 3; ++e) {
1547 index_t vertex_idx = mesh_struct_ptr[e];
1548 if (vertex_idx != -1) continue;
1549
1550 OPEN3D_ATOMIC_ADD(count_ptr, 1);
1551 }
1552 });
1553
1554#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1555 vertex_count = count.Item<index_t>();
1556#else
1557 vertex_count = (*count_ptr).load();
1558#endif
1559 }
1560
1561 utility::LogDebug("Total vertex count = {}", vertex_count);
1562 vertices = core::Tensor({vertex_count, 3}, core::Float32, device);
1563
1564 vertex_normals = core::Tensor({vertex_count, 3}, core::Float32, device);
1565 ArrayIndexer normal_indexer = ArrayIndexer(vertex_normals, 1);
1566
1567 ArrayIndexer color_indexer;
1568 if (color_base_ptr) {
1569 vertex_colors = core::Tensor({vertex_count, 3}, core::Float32, device);
1570 color_indexer = ArrayIndexer(vertex_colors, 1);
1571 }
1572
1573 ArrayIndexer block_keys_indexer(block_keys, 1);
1574 ArrayIndexer vertex_indexer(vertices, 1);
1575
1576#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1577 count = core::Tensor(std::vector<index_t>{0}, {}, core::Int32, device);
1578 count_ptr = count.GetDataPtr<index_t>();
1579#else
1580 (*count_ptr) = 0;
1581#endif
1582
1583 // Pass 2: extract vertices.
1584
1585 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t widx) {
1586 auto GetLinearIdx = [&] OPEN3D_DEVICE(
1587 index_t xo, index_t yo, index_t zo,
1588 index_t curr_block_idx) -> index_t {
1589 return DeviceGetLinearIdx(xo, yo, zo, curr_block_idx, resolution,
1590 nb_block_masks_indexer,
1591 nb_block_indices_indexer);
1592 };
1593
1594 auto GetNormal = [&] OPEN3D_DEVICE(index_t xo, index_t yo, index_t zo,
1595 index_t curr_block_idx, float* n) {
1596 return DeviceGetNormal<tsdf_t>(
1597 tsdf_base_ptr, xo, yo, zo, curr_block_idx, n, resolution,
1598 nb_block_masks_indexer, nb_block_indices_indexer);
1599 };
1600
1601 // Natural index (0, N) -> (block_idx, voxel_idx)
1602 index_t workload_block_idx = widx / resolution3;
1603 index_t block_idx = indices_ptr[workload_block_idx];
1604 index_t voxel_idx = widx % resolution3;
1605
1606 // block_idx -> (x_block, y_block, z_block)
1607 index_t* block_key_ptr =
1608 block_keys_indexer.GetDataPtr<index_t>(block_idx);
1609 index_t xb = block_key_ptr[0];
1610 index_t yb = block_key_ptr[1];
1611 index_t zb = block_key_ptr[2];
1612
1613 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1614 index_t xv, yv, zv;
1615 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1616
1617 // global coordinate (in voxels)
1618 index_t x = xb * resolution + xv;
1619 index_t y = yb * resolution + yv;
1620 index_t z = zb * resolution + zv;
1621
1622 // Obtain voxel's mesh struct ptr
1623 index_t* mesh_struct_ptr = mesh_structure_indexer.GetDataPtr<index_t>(
1624 xv, yv, zv, workload_block_idx);
1625
1626 // Early quit -- no allocated vertex to compute
1627 if (mesh_struct_ptr[0] != -1 && mesh_struct_ptr[1] != -1 &&
1628 mesh_struct_ptr[2] != -1) {
1629 return;
1630 }
1631
1632 // Obtain voxel ptr
1633 index_t linear_idx = resolution3 * block_idx + voxel_idx;
1634 float tsdf_o = tsdf_base_ptr[linear_idx];
1635
1636 float no[3] = {0}, ne[3] = {0};
1637
1638 // Get normal at origin
1639 GetNormal(xv, yv, zv, workload_block_idx, no);
1640
1641 // Enumerate 3 edges in the voxel
1642 for (index_t e = 0; e < 3; ++e) {
1643 index_t vertex_idx = mesh_struct_ptr[e];
1644 if (vertex_idx != -1) continue;
1645
1646 index_t linear_idx_e =
1647 GetLinearIdx(xv + (e == 0), yv + (e == 1), zv + (e == 2),
1648 workload_block_idx);
1649 OPEN3D_ASSERT(linear_idx_e > 0 &&
1650 "Internal error: GetVoxelAt returns nullptr.");
1651 float tsdf_e = tsdf_base_ptr[linear_idx_e];
1652 float ratio = (0 - tsdf_o) / (tsdf_e - tsdf_o);
1653
1654 index_t idx = OPEN3D_ATOMIC_ADD(count_ptr, 1);
1655 mesh_struct_ptr[e] = idx;
1656
1657 float ratio_x = ratio * index_t(e == 0);
1658 float ratio_y = ratio * index_t(e == 1);
1659 float ratio_z = ratio * index_t(e == 2);
1660
1661 float* vertex_ptr = vertex_indexer.GetDataPtr<float>(idx);
1662 vertex_ptr[0] = voxel_size * (x + ratio_x);
1663 vertex_ptr[1] = voxel_size * (y + ratio_y);
1664 vertex_ptr[2] = voxel_size * (z + ratio_z);
1665
1666 // Get normal at edge and interpolate
1667 float* normal_ptr = normal_indexer.GetDataPtr<float>(idx);
1668 GetNormal(xv + (e == 0), yv + (e == 1), zv + (e == 2),
1669 workload_block_idx, ne);
1670 float nx = (1 - ratio) * no[0] + ratio * ne[0];
1671 float ny = (1 - ratio) * no[1] + ratio * ne[1];
1672 float nz = (1 - ratio) * no[2] + ratio * ne[2];
1673 float norm = static_cast<float>(sqrt(nx * nx + ny * ny + nz * nz) +
1674 1e-5);
1675 normal_ptr[0] = nx / norm;
1676 normal_ptr[1] = ny / norm;
1677 normal_ptr[2] = nz / norm;
1678
1679 if (color_base_ptr) {
1680 float* color_ptr = color_indexer.GetDataPtr<float>(idx);
1681 float r_o = color_base_ptr[linear_idx * 3 + 0];
1682 float g_o = color_base_ptr[linear_idx * 3 + 1];
1683 float b_o = color_base_ptr[linear_idx * 3 + 2];
1684
1685 float r_e = color_base_ptr[linear_idx_e * 3 + 0];
1686 float g_e = color_base_ptr[linear_idx_e * 3 + 1];
1687 float b_e = color_base_ptr[linear_idx_e * 3 + 2];
1688
1689 color_ptr[0] = ((1 - ratio) * r_o + ratio * r_e) / 255.0f;
1690 color_ptr[1] = ((1 - ratio) * g_o + ratio * g_e) / 255.0f;
1691 color_ptr[2] = ((1 - ratio) * b_o + ratio * b_e) / 255.0f;
1692 }
1693 }
1694 });
1695
1696 // Pass 3: connect vertices and form triangles.
1697 index_t triangle_count = vertex_count * 3;
1698 triangles = core::Tensor({triangle_count, 3}, core::Int32, device);
1699 ArrayIndexer triangle_indexer(triangles, 1);
1700
1701#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1702 count = core::Tensor(std::vector<index_t>{0}, {}, core::Int32, device);
1703 count_ptr = count.GetDataPtr<index_t>();
1704#else
1705 (*count_ptr) = 0;
1706#endif
1707 core::ParallelFor(device, n, [=] OPEN3D_DEVICE(index_t widx) {
1708 // Natural index (0, N) -> (block_idx, voxel_idx)
1709 index_t workload_block_idx = widx / resolution3;
1710 index_t voxel_idx = widx % resolution3;
1711
1712 // voxel_idx -> (x_voxel, y_voxel, z_voxel)
1713 index_t xv, yv, zv;
1714 voxel_indexer.WorkloadToCoord(voxel_idx, &xv, &yv, &zv);
1715
1716 // Obtain voxel's mesh struct ptr
1717 index_t* mesh_struct_ptr = mesh_structure_indexer.GetDataPtr<index_t>(
1718 xv, yv, zv, workload_block_idx);
1719
1720 index_t table_idx = mesh_struct_ptr[3];
1721 if (tri_count[table_idx] == 0) return;
1722
1723 for (index_t tri = 0; tri < 16; tri += 3) {
1724 if (tri_table[table_idx][tri] == -1) return;
1725
1726 index_t tri_idx = OPEN3D_ATOMIC_ADD(count_ptr, 1);
1727
1728 for (index_t vertex = 0; vertex < 3; ++vertex) {
1729 index_t edge = tri_table[table_idx][tri + vertex];
1730
1731 index_t xv_i = xv + edge_shifts[edge][0];
1732 index_t yv_i = yv + edge_shifts[edge][1];
1733 index_t zv_i = zv + edge_shifts[edge][2];
1734 index_t edge_i = edge_shifts[edge][3];
1735
1736 index_t dxb = xv_i / resolution;
1737 index_t dyb = yv_i / resolution;
1738 index_t dzb = zv_i / resolution;
1739
1740 index_t nb_idx = (dxb + 1) + (dyb + 1) * 3 + (dzb + 1) * 9;
1741
1742 index_t block_idx_i =
1743 *nb_block_indices_indexer.GetDataPtr<index_t>(
1744 workload_block_idx, nb_idx);
1745 index_t* mesh_struct_ptr_i =
1746 mesh_structure_indexer.GetDataPtr<index_t>(
1747 xv_i - dxb * resolution,
1748 yv_i - dyb * resolution,
1749 zv_i - dzb * resolution,
1750 inv_indices_ptr[block_idx_i]);
1751
1752 index_t* triangle_ptr =
1753 triangle_indexer.GetDataPtr<index_t>(tri_idx);
1754 triangle_ptr[2 - vertex] = mesh_struct_ptr_i[edge_i];
1755 }
1756 }
1757 });
1758
1759#if defined(__CUDACC__) || defined(SYCL_LANGUAGE_VERSION)
1760 triangle_count = count.Item<index_t>();
1761#else
1762 triangle_count = (*count_ptr).load();
1763#endif
1764 utility::LogDebug("Total triangle count = {}", triangle_count);
1765 triangles = triangles.Slice(0, 0, triangle_count);
1766}
1767
1768} // namespace voxel_grid
1769} // namespace kernel
1770} // namespace geometry
1771} // namespace t
1772} // namespace open3d
#define OPEN3D_DEVICE
Definition CUDAUtils.h:44
OPEN3D_HOST_DEVICE int Sign(int x)
Definition GeometryMacros.h:92
#define OPEN3D_ATOMIC_ADD(X, Y)
Definition GeometryMacros.h:53
math::float4 color
Definition LineSetBuffers.cpp:45
#define OPEN3D_ASSERT(...)
Definition Macro.h:51
SYCL implementation of DeviceHashBackend (open addressing, in-tree).
Real weight
Definition SurfaceReconstructionPoisson.cpp:267
double t
Definition SurfaceReconstructionPoisson.cpp:172
Definition Device.h:18
static const Dtype Float64
Definition Dtype.h:24
Definition Tensor.h:32
T * GetDataPtr()
Definition Tensor.h:1201
static Tensor Zeros(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor fill with zeros.
Definition Tensor.cpp:405
static Tensor Eye(int64_t n, Dtype dtype, const Device &device)
Create an identity matrix of size n x n.
Definition Tensor.cpp:417
Definition TensorMap.h:31
Definition GeometryIndexer.h:161
OPEN3D_HOST_DEVICE bool InBoundary(float x, float y) const
Definition GeometryIndexer.h:294
OPEN3D_HOST_DEVICE void * GetDataPtr() const
Definition GeometryIndexer.h:315
Helper class for converting coordinates/indices between 3D/3D, 3D/2D, 2D/3D.
Definition GeometryIndexer.h:25
OPEN3D_HOST_DEVICE void Project(float x_in, float y_in, float z_in, float *u_out, float *v_out) const
Project a 3D coordinate in camera coordinate to a 2D uv coordinate.
Definition GeometryIndexer.h:100
OPEN3D_HOST_DEVICE void Rotate(float x_in, float y_in, float z_in, float *x_out, float *y_out, float *z_out) const
Transform a 3D coordinate in camera coordinate to world coordinate.
Definition GeometryIndexer.h:81
OPEN3D_HOST_DEVICE void RigidTransform(float x_in, float y_in, float z_in, float *x_out, float *y_out, float *z_out) const
Transform a 3D coordinate in camera coordinate to world coordinate.
Definition GeometryIndexer.h:62
OPEN3D_HOST_DEVICE void Unproject(float u_in, float v_in, float d_in, float *x_out, float *y_out, float *z_out) const
Unproject a 2D uv coordinate with depth to 3D in camera coordinate.
Definition GeometryIndexer.h:111
int count
Definition FilePCD.cpp:43
int offset
Definition FilePCD.cpp:46
int points
Definition FilePCD.cpp:55
void Synchronize()
Definition CUDAUtils.cpp:58
uint32_t buf_index_t
Definition HashBackendBuffer.h:49
const Dtype Int32
Definition Dtype.cpp:46
void ParallelFor(const Device &device, int64_t n, const func_t &func)
Definition ParallelFor.h:135
const Dtype Float32
Definition Dtype.cpp:42
const char const char value recording_handle imu_sample recording_handle uint8_t size_t data_size k4a_record_configuration_t config target_format k4a_capture_t capture_handle k4a_imu_sample_t imu_sample playback_handle k4a_logging_message_cb_t void min_level device_handle k4a_imu_sample_t timeout_in_ms capture_handle capture_handle capture_handle image_handle temperature_c int
Definition K4aPlugin.cpp:474
void ExtractPointCloudCPU(const core::Tensor &block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &points, core::Tensor &normals, core::Tensor &colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &valid_size)
Definition VoxelBlockGridImpl.h:1114
void GetVoxelCoordinatesAndFlattenedIndicesCPU(const core::Tensor &buf_indices, const core::Tensor &block_keys, core::Tensor &voxel_coords, core::Tensor &flattened_indices, index_t block_resolution, float voxel_size)
Definition VoxelBlockGridImpl.h:46
OPEN3D_DEVICE index_t DeviceGetLinearIdx(index_t xo, index_t yo, index_t zo, index_t curr_block_idx, index_t resolution, const ArrayIndexer &nb_block_masks_indexer, const ArrayIndexer &nb_block_indices_indexer)
Definition VoxelBlockGridImpl.h:91
void IntegrateCPU(const core::Tensor &depth, const core::Tensor &color, const core::Tensor &block_indices, const core::Tensor &block_keys, TensorMap &block_value_map, const core::Tensor &depth_intrinsic, const core::Tensor &color_intrinsic, const core::Tensor &extrinsic, index_t resolution, float voxel_size, float sdf_trunc, float depth_scale, float depth_max)
Definition VoxelBlockGridImpl.h:159
TArrayIndexer< index_t > ArrayIndexer
Definition VoxelBlockGridImpl.h:37
void ExtractTriangleMeshCPU(const core::Tensor &block_indices, const core::Tensor &inv_block_indices, const core::Tensor &nb_block_indices, const core::Tensor &nb_block_masks, const core::Tensor &block_keys, const TensorMap &block_value_map, core::Tensor &vertices, core::Tensor &triangles, core::Tensor &vertex_normals, core::Tensor &vertex_colors, index_t block_resolution, float voxel_size, float weight_threshold, index_t &vertex_count)
Definition VoxelBlockGridImpl.h:1375
OPEN3D_DEVICE void DeviceGetNormal(const tsdf_t *tsdf_base_ptr, index_t xo, index_t yo, index_t zo, index_t curr_block_idx, float *n, index_t resolution, const ArrayIndexer &nb_block_masks_indexer, const ArrayIndexer &nb_block_indices_indexer)
Definition VoxelBlockGridImpl.h:120
void RayCastCPU(std::shared_ptr< core::HashMap > &hashmap, const TensorMap &block_value_map, const core::Tensor &range_map, TensorMap &renderings_map, const core::Tensor &intrinsic, const core::Tensor &extrinsic, index_t h, index_t w, index_t block_resolution, float voxel_size, float depth_scale, float depth_min, float depth_max, float weight_threshold, float trunc_voxel_multiplier, int range_map_down_factor)
Definition VoxelBlockGridImpl.h:570
int index_t
Definition VoxelBlockGrid.h:22
void EstimateRangeCPU(const core::Tensor &block_keys, core::Tensor &range_minmax_map, const core::Tensor &intrinsics, const core::Tensor &extrinsics, int h, int w, int down_factor, int64_t block_resolution, float voxel_size, float depth_min, float depth_max, core::Tensor &fragment_buffer)
Definition VoxelBlockGridImpl.h:313
core::Tensor InverseTransformation(const core::Tensor &T)
TODO(wei): find a proper place for such functionalities.
Definition Utility.h:77
Definition PinholeCameraIntrinsic.cpp:16
void OPEN3D_DEVICE Update(index_t xin, index_t yin, index_t zin, index_t block_idx_in)
Definition VoxelBlockGridImpl.h:551
index_t x
Definition VoxelBlockGridImpl.h:542
index_t block_idx
Definition VoxelBlockGridImpl.h:545
index_t z
Definition VoxelBlockGridImpl.h:544
index_t y
Definition VoxelBlockGridImpl.h:543
index_t OPEN3D_DEVICE Check(index_t xin, index_t yin, index_t zin)
Definition VoxelBlockGridImpl.h:547
Definition Dispatch.h:84
Definition Dispatch.h:68
Definition MiniVec.h:24
const core::Tensor * normals
Definition TriangleMesh.cpp:2126
const core::Tensor * indices
Definition TriangleMesh.cpp:2128