ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
TriangleMeshCPU.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <Parallel.h>
9 
10 #include <cstddef>
11 
12 #include "cloudViewer/core/Dtype.h"
16 
17 namespace cloudViewer {
18 namespace t {
19 namespace geometry {
20 namespace kernel {
21 namespace trianglemesh {
22 
23 void ComputeVertexNormalsCPU(const core::Tensor& triangles,
24  const core::Tensor& triangle_normals,
25  core::Tensor& vertex_normals) {
26  const core::Dtype dtype = vertex_normals.GetDtype();
27  const int64_t n = triangles.GetLength();
28  const core::Tensor triangles_d = triangles.To(core::Int64);
29 
30  DISPATCH_DTYPE_TO_TEMPLATE(dtype, [&]() {
31  const int64_t* triangle_ptr = triangles_d.GetDataPtr<int64_t>();
32  const scalar_t* triangle_normals_ptr =
33  triangle_normals.GetDataPtr<scalar_t>();
34  scalar_t* vertex_normals_ptr = vertex_normals.GetDataPtr<scalar_t>();
35 
36  for (int64_t i = 0; i < n; ++i) {
37  int64_t idx = 3 * i;
38  int64_t triangle_id1 = triangle_ptr[idx];
39  int64_t triangle_id2 = triangle_ptr[idx + 1];
40  int64_t triangle_id3 = triangle_ptr[idx + 2];
41 
42  scalar_t n1 = triangle_normals_ptr[idx];
43  scalar_t n2 = triangle_normals_ptr[idx + 1];
44  scalar_t n3 = triangle_normals_ptr[idx + 2];
45 
46  vertex_normals_ptr[3 * triangle_id1] += n1;
47  vertex_normals_ptr[3 * triangle_id1 + 1] += n2;
48  vertex_normals_ptr[3 * triangle_id1 + 2] += n3;
49  vertex_normals_ptr[3 * triangle_id2] += n1;
50  vertex_normals_ptr[3 * triangle_id2 + 1] += n2;
51  vertex_normals_ptr[3 * triangle_id2 + 2] += n3;
52  vertex_normals_ptr[3 * triangle_id3] += n1;
53  vertex_normals_ptr[3 * triangle_id3 + 1] += n2;
54  vertex_normals_ptr[3 * triangle_id3 + 2] += n3;
55  }
56  });
57 }
58 
59 template <typename T>
60 void mix_3x3(T* out, const T* a, const T* b, const T* c, float wts[3]) {
61  out[0] = wts[0] * a[0] + wts[1] * b[0] + wts[2] * c[0];
62  out[1] = wts[0] * a[1] + wts[1] * b[1] + wts[2] * c[1];
63  out[2] = wts[0] * a[2] + wts[1] * b[2] + wts[2] * c[2];
64 }
65 template void mix_3x3<float>(float* out,
66  const float* a,
67  const float* b,
68  const float* c,
69  float wts[3]);
70 
76 std::array<core::Tensor, 3> SamplePointsUniformlyCPU(
77  const core::Tensor& triangles,
78  const core::Tensor& vertices,
79  const core::Tensor& triangle_areas,
80  const core::Tensor& vertex_normals,
81  const core::Tensor& vertex_colors,
82  const core::Tensor& triangle_normals,
83  const core::Tensor& texture_uvs,
84  const core::Tensor& albedo,
85  size_t number_of_points) {
86  utility::random::UniformRealGenerator<float> uniform_generator(0.0, 1.0);
88  {static_cast<int64_t>(number_of_points), 3}, vertices.GetDtype());
90  bool use_vert_normal = vertex_normals.NumElements() > 0,
91  use_triangle_normal = triangle_normals.NumElements() > 0,
92  use_vert_colors = vertex_colors.NumElements() > 0,
93  use_albedo = albedo.NumElements() > 0 && texture_uvs.NumElements() > 0;
94  if (use_vert_normal || use_triangle_normal) {
96  {static_cast<int64_t>(number_of_points), 3}, points.GetDtype());
97  }
98  if (use_albedo || use_vert_colors) {
100  {static_cast<int64_t>(number_of_points), 3}, core::Float32);
101  }
102  const size_t tex_width = use_albedo ? albedo.GetShape(1) : 0,
103  tex_height = use_albedo ? albedo.GetShape(0) : 0;
105  vertices.GetDtype(), triangles.GetDtype(), [&]() {
106  const int_t* p_triangles = triangles.GetDataPtr<int_t>();
107  const scalar_t* p_vertices = vertices.GetDataPtr<scalar_t>();
108  const scalar_t* p_vert_normals =
109  use_vert_normal ? vertex_normals.GetDataPtr<scalar_t>()
110  : nullptr;
111  const float* p_vert_colors =
112  use_vert_colors ? vertex_colors.GetDataPtr<float>()
113  : nullptr;
114  const scalar_t* p_tri_normals =
115  use_triangle_normal
116  ? triangle_normals.GetDataPtr<scalar_t>()
117  : nullptr;
118  const scalar_t* p_tri_uvs =
119  use_albedo ? texture_uvs.GetDataPtr<scalar_t>()
120  : nullptr;
121  const float* p_albedo =
122  use_albedo ? albedo.GetDataPtr<float>() : nullptr;
123 
124  scalar_t* p_points = points.GetDataPtr<scalar_t>();
125  scalar_t* p_normals = (use_vert_normal || use_triangle_normal)
126  ? normals.GetDataPtr<scalar_t>()
127  : nullptr;
128  float* p_colors = (use_albedo || use_vert_colors)
129  ? colors.GetDataPtr<float>()
130  : nullptr;
131 
132  utility::random::DiscreteGenerator<size_t>
133  triangle_index_generator(
134  triangle_areas.GetDataPtr<scalar_t>(),
135  triangle_areas.GetDataPtr<scalar_t>() +
136  triangles.GetLength());
137  // TODO(SS): Parallelize this.
138  for (size_t point_idx = 0; point_idx < number_of_points;
139  ++point_idx, p_points += 3) {
140  float r1 = uniform_generator();
141  float r2 = uniform_generator();
142  float wts[3] = {1 - std::sqrt(r1), std::sqrt(r1) * (1 - r2),
143  std::sqrt(r1) * r2};
144  size_t tidx = triangle_index_generator();
145  int_t vert_idx[3] = {p_triangles[3 * tidx + 0],
146  p_triangles[3 * tidx + 1],
147  p_triangles[3 * tidx + 2]};
148 
149  mix_3x3(p_points, p_vertices + 3 * vert_idx[0],
150  p_vertices + 3 * vert_idx[1],
151  p_vertices + 3 * vert_idx[2], wts);
152 
153  if (use_vert_normal) {
154  mix_3x3(p_normals, p_vert_normals + 3 * vert_idx[0],
155  p_vert_normals + 3 * vert_idx[1],
156  p_vert_normals + 3 * vert_idx[2], wts);
157  p_normals += 3;
158  } else if (use_triangle_normal) {
159  std::copy(p_tri_normals + 3 * tidx,
160  p_tri_normals + 3 * (tidx + 1), p_normals);
161  p_normals += 3;
162  }
163  // if there is a texture, sample from texture nearest nbr
164  // pixel instead
165  if (use_albedo) {
166  float u = wts[0] * p_tri_uvs[6 * tidx] +
167  wts[1] * p_tri_uvs[6 * tidx + 2] +
168  wts[2] * p_tri_uvs[6 * tidx + 4];
169  float v = wts[0] * p_tri_uvs[6 * tidx + 1] +
170  wts[1] * p_tri_uvs[6 * tidx + 3] +
171  wts[2] * p_tri_uvs[6 * tidx + 5];
172  size_t x = u * tex_width, y = v * tex_height;
173  std::copy(p_albedo + 3 * (y * tex_width + x),
174  p_albedo + 3 * (y * tex_width + x + 1),
175  p_colors);
176  p_colors += 3;
177  } // if there is no texture, sample from vertex color
178  else if (use_vert_colors) {
179  mix_3x3(p_colors, p_vert_colors + 3 * vert_idx[0],
180  p_vert_colors + 3 * vert_idx[1],
181  p_vert_colors + 3 * vert_idx[2], wts);
182  p_colors += 3;
183  }
184  }
185  });
186  return {points, normals, colors};
187 }
188 } // namespace trianglemesh
189 } // namespace kernel
190 } // namespace geometry
191 } // namespace t
192 } // namespace cloudViewer
#define DISPATCH_DTYPE_TO_TEMPLATE(DTYPE,...)
Definition: Dispatch.h:31
#define DISPATCH_FLOAT_INT_DTYPE_TO_TEMPLATE(FDTYPE, IDTYPE,...)
Definition: Dispatch.h:91
int points
int64_t GetLength() const
Definition: Tensor.h:1125
Dtype GetDtype() const
Definition: Tensor.h:1164
int64_t NumElements() const
Definition: Tensor.h:1170
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Definition: Tensor.cpp:400
SizeVector GetShape() const
Definition: Tensor.h:1127
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
double colors[3]
double normals[3]
const Dtype Int64
Definition: Dtype.cpp:47
const Dtype Float32
Definition: Dtype.cpp:42
void mix_3x3(T *out, const T *a, const T *b, const T *c, float wts[3])
void ComputeVertexNormalsCPU(const core::Tensor &triangles, const core::Tensor &triangle_normals, core::Tensor &vertex_normals)
std::array< core::Tensor, 3 > SamplePointsUniformlyCPU(const core::Tensor &triangles, const core::Tensor &vertices, const core::Tensor &triangle_areas, const core::Tensor &vertex_normals, const core::Tensor &vertex_colors, const core::Tensor &triangle_normals, const core::Tensor &texture_uvs, const core::Tensor &albedo, size_t number_of_points)
template void mix_3x3< float >(float *out, const float *a, const float *b, const float *c, float wts[3])
Generic file read and write utility for python interface.