ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
GaussianSplatBuffers.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 // 4068: Filament has some clang-specific vectorizing pragma's that MSVC flags
9 // 4146: Filament's utils/algorithm.h utils::details::ctz() tries to negate
10 // an unsigned int.
11 // 4293: Filament's utils/algorithm.h utils::details::clz() does strange
12 // things with MSVC. Somehow sizeof(unsigned int) > 4, but its size is
13 // 32 so that x >> 32 gives a warning. (Or maybe the compiler can't
14 // determine the if statement does not run.)
15 #ifdef _MSC_VER
16 #pragma warning(push)
17 #pragma warning(disable : 4068 4146 4293)
18 #endif // _MSC_VER
19 
20 #include <filament/IndexBuffer.h>
21 #include <filament/VertexBuffer.h>
22 #include <geometry/SurfaceOrientation.h>
23 
24 #ifdef _MSC_VER
25 #pragma warning(pop)
26 #endif // _MSC_VER
27 
34 
35 using namespace filament;
36 
37 namespace cloudViewer {
38 namespace visualization {
39 namespace rendering {
40 TGaussianSplatBuffersBuilder::TGaussianSplatBuffersBuilder(
41  const t::geometry::PointCloud& geometry)
42  : TPointCloudBuffersBuilder(geometry) {
43  std::vector<std::string> check_list = {"f_dc", "opacity", "rot", "scale",
44  "f_rest"};
45  for (const auto& check_item : check_list) {
46  if (check_item == "f_rest" && !geometry_.HasPointAttr(check_item)) {
47  continue;
48  }
49  if (geometry_.GetPointAttr(check_item).GetDtype() != core::Float32) {
50  auto check_item_instance = geometry_.GetPointAttr(check_item);
52  "Tensor gaussian splat {} must have DType of Float32 not "
53  "{}. "
54  "Converting.",
55  check_item, check_item_instance.GetDtype().ToString());
56  geometry_.GetPointAttr(check_item) =
57  check_item_instance.To(core::Float32);
58  }
59  }
60 }
61 
64  auto& engine = EngineInstance::GetInstance();
65  auto& resource_mgr = EngineInstance::GetResourceManager();
66 
67  const auto& points = geometry_.GetPointPositions();
68  const size_t n_vertices = points.GetLength();
69 
70  int sh_degree = geometry_.GaussianSplatGetSHOrder();
71  if (sh_degree > 2) {
73  "Rendering for Gaussian splats with SH degrees higher than 2 "
74  "is not supported. They are processed as SH degree 2.");
75  sh_degree = 2;
76  }
77 
78  int f_rest_coeffs_count = sh_degree * (sh_degree + 2) * 3;
79  int f_rest_buffer_count = (f_rest_coeffs_count % 4 == 0)
80  ? (f_rest_coeffs_count / 4)
81  : std::ceil(f_rest_coeffs_count / 4.0);
82 
83  int base_buffer_count = 5;
84  int all_buffer_count = base_buffer_count + f_rest_buffer_count;
85 
86  // we use POSITION for positions, COLOR for scale, CUSTOM7 for rot
87  // CUSTOM0 for f_dc and opacity, CUSTOM1-CUSTOM6 for f_rest.
88  VertexBuffer::Builder buffer_builder =
89  VertexBuffer::Builder()
90  .bufferCount(all_buffer_count)
91  .vertexCount(uint32_t(n_vertices))
92  .attribute(VertexAttribute::POSITION, 0,
93  VertexBuffer::AttributeType::FLOAT3)
94  .attribute(VertexAttribute::COLOR, 1,
95  VertexBuffer::AttributeType::FLOAT4)
96  .attribute(VertexAttribute::TANGENTS, 2,
97  VertexBuffer::AttributeType::FLOAT)
98  .attribute(VertexAttribute::CUSTOM0, 3,
99  VertexBuffer::AttributeType::FLOAT4)
100  .attribute(VertexAttribute::CUSTOM7, 4,
101  VertexBuffer::AttributeType::FLOAT4);
102  if (sh_degree >= 1) {
103  buffer_builder.attribute(VertexAttribute::CUSTOM1, 5,
104  VertexBuffer::AttributeType::FLOAT4);
105  buffer_builder.attribute(VertexAttribute::CUSTOM2, 6,
106  VertexBuffer::AttributeType::FLOAT4);
107  buffer_builder.attribute(VertexAttribute::CUSTOM3, 7,
108  VertexBuffer::AttributeType::FLOAT4);
109  }
110  if (sh_degree == 2) {
111  buffer_builder.attribute(VertexAttribute::CUSTOM4, 8,
112  VertexBuffer::AttributeType::FLOAT4);
113  buffer_builder.attribute(VertexAttribute::CUSTOM5, 9,
114  VertexBuffer::AttributeType::FLOAT4);
115  buffer_builder.attribute(VertexAttribute::CUSTOM6, 10,
116  VertexBuffer::AttributeType::FLOAT4);
117  }
118 
119  VertexBuffer* vbuf = buffer_builder.build(engine);
120 
121  VertexBufferHandle vb_handle;
122  if (vbuf) {
123  vb_handle = resource_mgr.AddVertexBuffer(vbuf);
124  } else {
125  return {};
126  }
127 
128  const size_t vertex_array_size = n_vertices * 3 * sizeof(float);
129  float* vertex_array = static_cast<float*>(malloc(vertex_array_size));
130  memcpy(vertex_array, points.GetDataPtr(), vertex_array_size);
131  VertexBuffer::BufferDescriptor pts_descriptor(
132  vertex_array, vertex_array_size,
134  vbuf->setBufferAt(engine, 0, std::move(pts_descriptor));
135 
136  const size_t scale_array_size = n_vertices * 4 * sizeof(float);
137  float* scale_array = static_cast<float*>(malloc(scale_array_size));
138  std::memset(scale_array, 0, scale_array_size);
139  float* scale_src = geometry_.GetPointAttr("scale").GetDataPtr<float>();
140  for (size_t i = 0; i < n_vertices; i++) {
141  std::memcpy(scale_array + i * 4, scale_src + i * 3, 3 * sizeof(float));
142  }
143  VertexBuffer::BufferDescriptor scale_descriptor(
144  scale_array, scale_array_size,
146  vbuf->setBufferAt(engine, 1, std::move(scale_descriptor));
147 
148  // We need to allocate a buffer for TANGENTS; otherwise, Filament will issue
149  // a warning.
150  const size_t empty_array_size = n_vertices * sizeof(float);
151  float* empty_array = static_cast<float*>(malloc(empty_array_size));
152  std::memset(empty_array, 0, empty_array_size);
153  VertexBuffer::BufferDescriptor empty_descriptor(
154  empty_array, empty_array_size,
156  vbuf->setBufferAt(engine, 2, std::move(empty_descriptor));
157 
158  const size_t color_array_size = n_vertices * 4 * sizeof(float);
159  float* color_array = static_cast<float*>(malloc(color_array_size));
160  float* f_dc_ptr = geometry_.GetPointAttr("f_dc").GetDataPtr<float>();
161  float* opacity_ptr = geometry_.GetPointAttr("opacity").GetDataPtr<float>();
162  for (size_t i = 0; i < n_vertices; i++) {
163  std::memcpy(color_array + i * 4, f_dc_ptr + i * 3, 3 * sizeof(float));
164  std::memcpy(color_array + i * 4 + 3, opacity_ptr + i, sizeof(float));
165  }
166  VertexBuffer::BufferDescriptor color_descriptor(
167  color_array, color_array_size,
169  vbuf->setBufferAt(engine, 3, std::move(color_descriptor));
170 
171  const size_t rot_array_size = n_vertices * 4 * sizeof(float);
172  float* rot_array = static_cast<float*>(malloc(rot_array_size));
173  std::memcpy(rot_array, geometry_.GetPointAttr("rot").GetDataPtr(),
174  rot_array_size);
175  VertexBuffer::BufferDescriptor rot_descriptor(
176  rot_array, rot_array_size,
178  vbuf->setBufferAt(engine, 4, std::move(rot_descriptor));
179 
180  int data_count_in_one_buffer = 4;
181  const size_t f_rest_array_size =
182  n_vertices * data_count_in_one_buffer * sizeof(float);
183  const size_t custom_buffer_start_index = 5;
184  float* f_rest_src =
185  (f_rest_buffer_count > 0)
186  ? geometry_.GetPointAttr("f_rest").GetDataPtr<float>()
187  : nullptr;
188  for (int i = 0; i < f_rest_buffer_count; i++) {
189  float* f_rest_array = static_cast<float*>(malloc(f_rest_array_size));
190 
191  size_t copy_data_size = f_rest_array_size;
192  if (i == f_rest_buffer_count - 1) {
193  int remaining_count_in_last_iter =
194  data_count_in_one_buffer +
195  (f_rest_coeffs_count -
196  f_rest_buffer_count * data_count_in_one_buffer);
197  copy_data_size =
198  n_vertices * remaining_count_in_last_iter * sizeof(float);
199  std::memset(f_rest_array, 0, f_rest_array_size);
200  }
201 
202  std::memcpy(f_rest_array,
203  f_rest_src + i * n_vertices * data_count_in_one_buffer,
204  copy_data_size);
205  VertexBuffer::BufferDescriptor f_rest_descriptor(
206  f_rest_array, f_rest_array_size,
208  vbuf->setBufferAt(engine, custom_buffer_start_index + i,
209  std::move(f_rest_descriptor));
210  }
211 
212  auto ib_handle = CreateIndexBuffer(n_vertices);
213 
214  IndexBufferHandle downsampled_handle;
215  if (n_vertices >= downsample_threshold_) {
216  downsampled_handle =
218  }
219 
220  return std::make_tuple(vb_handle, ib_handle, downsampled_handle);
221 }
222 } // namespace rendering
223 } // namespace visualization
224 } // namespace cloudViewer
int points
A point cloud contains a list of 3D points.
Definition: PointCloud.h:82
int GaussianSplatGetSHOrder() const
Returns the order of spherical harmonics used for Gaussian Splatting. Returns 0 if f_rest is not pres...
bool HasPointAttr(const std::string &key) const
Definition: PointCloud.h:207
core::Tensor & GetPointPositions()
Get the value of the "positions" attribute. Convenience function.
Definition: PointCloud.h:124
const TensorMap & GetPointAttr() const
Getter for point_attr_ TensorMap. Used in Pybind.
Definition: PointCloud.h:111
static FilamentResourceManager & GetResourceManager()
static IndexBufferHandle CreateIndexBuffer(size_t max_index, size_t n_subsamples=SIZE_MAX)
static void DeallocateBuffer(void *buffer, size_t size, void *user_ptr)
std::tuple< VertexBufferHandle, IndexBufferHandle, IndexBufferHandle > Buffers
Buffers ConstructBuffers() override
Constructs vertex and index buffers for Gaussian Splat rendering.
#define LogWarning(...)
Definition: Logging.h:72
const Dtype Float32
Definition: Dtype.cpp:42
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
Generic file read and write utility for python interface.