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