17 #pragma warning(disable : 4068 4146 4293)
20 #include <filament/Engine.h>
21 #include <filament/IndexBuffer.h>
22 #include <filament/MaterialEnums.h>
23 #include <filament/Scene.h>
24 #include <filament/TransformManager.h>
25 #include <filament/VertexBuffer.h>
26 #include <geometry/SurfaceOrientation.h>
45 namespace visualization {
52 math::quatf
tangent = {0.f, 0.f, 0.f, 1.f};
55 struct ColoredVertex {
56 math::float3
position = {0.f, 0.f, 0.f};
57 math::quatf
tangent = {0.f, 0.f, 0.f, 1.f};
58 math::float4
color = {0.5f, 0.5f, 0.5f, 1.f};
61 struct TexturedVertex {
62 math::float3
position = {0.f, 0.f, 0.f};
63 math::quatf
tangent = {0.f, 0.f, 0.f, 1.f};
64 math::float4
color = {0.5f, 0.5f, 0.5f, 1.f};
65 math::float2
uv = {0.f, 0.f};
68 template <
typename VertexType>
69 void SetVertexPosition(VertexType& vertex,
const Eigen::Vector3d& pos) {
70 auto float_pos = pos.cast<
float>();
71 vertex.position.x = float_pos(0);
72 vertex.position.y = float_pos(1);
73 vertex.position.z = float_pos(2);
76 template <
typename VertexType>
77 void SetVertexColor(VertexType& vertex,
const Eigen::Vector3d& c) {
78 auto float_color = c.cast<
float>();
79 vertex.color.x = float_color(0);
80 vertex.color.y = float_color(1);
81 vertex.color.z = float_color(2);
84 template <
typename VertexType>
85 void SetVertexUV(VertexType& vertex,
const Eigen::Vector2d& UV) {
86 auto float_uv = UV.cast<
float>();
87 vertex.uv.x = float_uv(0);
88 vertex.uv.y = float_uv(1);
91 template <
typename VertexType>
92 std::uint32_t GetVertexPositionOffset() {
96 template <
typename VertexType>
97 std::uint32_t GetVertexTangentOffset() {
101 template <
typename VertexType>
102 std::uint32_t GetVertexColorOffset() {
106 template <
typename VertexType>
107 std::uint32_t GetVertexUVOffset() {
111 template <
typename VertexType>
112 std::uint32_t GetVertexStride() {
113 return sizeof(VertexType);
116 VertexBuffer* BuildFilamentVertexBuffer(filament::Engine& engine,
118 const std::uint32_t
stride,
124 VertexBuffer::Builder()
127 .attribute(VertexAttribute::POSITION, 0,
128 VertexBuffer::AttributeType::FLOAT3,
129 GetVertexPositionOffset<TexturedVertex>(),
131 .normalized(VertexAttribute::TANGENTS)
132 .attribute(VertexAttribute::TANGENTS, 0,
133 VertexBuffer::AttributeType::FLOAT4,
134 GetVertexTangentOffset<TexturedVertex>(),
stride)
135 .attribute(VertexAttribute::CUSTOM0, 0,
136 VertexBuffer::AttributeType::FLOAT4,
137 GetVertexTangentOffset<TexturedVertex>(),
141 builder.normalized(VertexAttribute::COLOR)
142 .attribute(VertexAttribute::COLOR, 0,
143 VertexBuffer::AttributeType::FLOAT4,
144 GetVertexColorOffset<TexturedVertex>(),
stride);
148 builder.attribute(VertexAttribute::UV0, 0,
149 VertexBuffer::AttributeType::FLOAT2,
150 GetVertexUVOffset<TexturedVertex>(),
stride);
153 return builder.build(engine);
165 GeometryBuffersBuilder::IndexType*
bytes =
nullptr;
170 std::tuple<vbdata, ibdata> CreatePlainBuffers(
const math::quatf* tangents,
176 vertex_data.byte_count = vertex_data.vertices_count *
sizeof(BaseVertex);
177 vertex_data.bytes_to_copy = vertex_data.byte_count;
178 vertex_data.bytes = malloc(vertex_data.byte_count);
180 const BaseVertex kDefault;
181 auto plain_vertices =
static_cast<BaseVertex*
>(vertex_data.bytes);
182 for (
size_t i = 0; i < vertex_data.vertices_count; ++i) {
183 BaseVertex& element = plain_vertices[i];
185 SetVertexPosition(element, geometry.
getVertice(i));
186 if (tangents !=
nullptr) {
187 element.tangent = tangents[i];
189 element.tangent = kDefault.tangent;
193 index_data.stride =
sizeof(GeometryBuffersBuilder::IndexType);
194 index_data.byte_count = geometry.
size() * 3 * index_data.stride;
195 index_data.bytes =
static_cast<GeometryBuffersBuilder::IndexType*
>(
196 malloc(index_data.byte_count));
197 for (
size_t i = 0; i < geometry.
size(); ++i) {
199 index_data.bytes[3 * i] = triangle(0);
200 index_data.bytes[3 * i + 1] = triangle(1);
201 index_data.bytes[3 * i + 2] = triangle(2);
204 return std::make_tuple(vertex_data, index_data);
208 std::tuple<vbdata, ibdata> CreateColoredBuffers(
const math::quatf* tangents,
214 vertex_data.byte_count =
215 vertex_data.vertices_count *
sizeof(TexturedVertex);
216 vertex_data.bytes_to_copy = vertex_data.byte_count;
217 vertex_data.bytes = malloc(vertex_data.byte_count);
219 const TexturedVertex kDefault;
220 auto vertices =
static_cast<TexturedVertex*
>(vertex_data.bytes);
221 for (
size_t i = 0; i < vertex_data.vertices_count; ++i) {
222 TexturedVertex& element = vertices[i];
224 SetVertexPosition(element, geometry.
getVertice(i));
225 if (tangents !=
nullptr) {
226 element.tangent = tangents[i];
228 element.tangent = kDefault.tangent;
234 element.color = kDefault.color;
238 index_data.stride =
sizeof(GeometryBuffersBuilder::IndexType);
239 index_data.byte_count = geometry.
size() * 3 * index_data.stride;
240 index_data.bytes =
static_cast<GeometryBuffersBuilder::IndexType*
>(
241 malloc(index_data.byte_count));
242 for (
size_t i = 0; i < geometry.
size(); ++i) {
244 index_data.bytes[3 * i] = triangle(0);
245 index_data.bytes[3 * i + 1] = triangle(1);
246 index_data.bytes[3 * i + 2] = triangle(2);
249 return std::make_tuple(vertex_data, index_data);
253 std::tuple<vbdata, ibdata> CreateTexturedBuffers(
const math::quatf* tangents,
259 LookupKey() =
default;
260 explicit LookupKey(
const Eigen::Vector3d& pos,
261 const Eigen::Vector2d&
uv) {
271 bool operator<(
const LookupKey& other)
const {
272 for (
int i = 0; i < 5; ++i) {
273 double diff =
abs(values[i] - other.values[i]);
274 if (diff > kEpsilon) {
275 return values[i] < other.values[i];
282 const double kEpsilon = 0.00001;
283 double values[5] = {0};
286 std::map<LookupKey, std::pair<GeometryBuffersBuilder::IndexType,
287 GeometryBuffersBuilder::IndexType>>
290 index_data.stride =
sizeof(GeometryBuffersBuilder::IndexType);
291 index_data.byte_count = geometry.
size() * 3 * index_data.stride;
292 index_data.bytes =
static_cast<GeometryBuffersBuilder::IndexType*
>(
293 malloc(index_data.byte_count));
295 vertex_data.byte_count = geometry.
size() * 3 *
sizeof(TexturedVertex);
296 vertex_data.bytes = malloc(vertex_data.byte_count);
298 GeometryBuffersBuilder::IndexType free_idx = 0;
299 GeometryBuffersBuilder::IndexType uv_idx = 0;
300 auto textured_vertices =
static_cast<TexturedVertex*
>(vertex_data.bytes);
302 const TexturedVertex kDefault;
303 for (
size_t i = 0; i < geometry.
size(); ++i) {
306 for (
size_t j = 0; j < 3; ++j) {
307 GeometryBuffersBuilder::IndexType index = triangle(j);
312 LookupKey lookup_key(pos,
uv);
313 auto found = index_lookup.find(lookup_key);
314 if (found != index_lookup.end()) {
315 index = found->second.first;
318 GeometryBuffersBuilder::IndexType source_idx = triangle(j);
320 index_lookup[lookup_key] = {free_idx, source_idx};
323 TexturedVertex& element = textured_vertices[index];
324 SetVertexPosition(element, pos);
325 if (tangents !=
nullptr) {
326 element.tangent = tangents[source_idx];
328 element.tangent = kDefault.tangent;
331 SetVertexUV(element,
uv);
334 SetVertexColor(element,
337 element.color = kDefault.color;
341 index_data.bytes[3 * i + j] = index;
347 vertex_data.vertices_count = free_idx;
348 vertex_data.bytes_to_copy =
349 vertex_data.vertices_count *
sizeof(TexturedVertex);
351 return std::make_tuple(vertex_data, index_data);
356 TriangleMeshBuffersBuilder::TriangleMeshBuffersBuilder(
const ccMesh& geometry)
357 : geometry_(geometry) {}
361 return RenderableManager::PrimitiveType::TRIANGLES;
370 math::quatf* float4v_tangents =
nullptr;
373 std::vector<Eigen::Vector3f>
normals;
375 for (
size_t i = 0; i < n_vertices; ++i) {
380 const size_t tangents_byte_count = n_vertices * 4 *
sizeof(float);
382 static_cast<math::quatf*
>(malloc(tangents_byte_count));
383 auto orientation = filament::geometry::SurfaceOrientation::Builder()
384 .vertexCount(n_vertices)
385 .normals(
reinterpret_cast<math::float3*
>(
388 orientation->getQuats(float4v_tangents, n_vertices);
397 std::tuple<vbdata, ibdata> buffers_data;
398 size_t stride =
sizeof(BaseVertex);
400 buffers_data = CreateTexturedBuffers(float4v_tangents, geometry_);
401 stride =
sizeof(TexturedVertex);
403 buffers_data = CreateColoredBuffers(float4v_tangents, geometry_);
404 stride =
sizeof(TexturedVertex);
407 buffers_data = CreatePlainBuffers(float4v_tangents, geometry_);
410 free(float4v_tangents);
412 const vbdata& vertex_data = std::get<0>(buffers_data);
413 const ibdata& index_data = std::get<1>(buffers_data);
416 vbuf = BuildFilamentVertexBuffer(
417 engine, std::uint32_t(vertex_data.vertices_count),
422 vb_handle = resource_mgr.AddVertexBuffer(vbuf);
424 free(vertex_data.bytes);
425 free(index_data.bytes);
432 VertexBuffer::BufferDescriptor vb_descriptor(vertex_data.bytes,
433 vertex_data.bytes_to_copy);
435 vbuf->setBufferAt(engine, 0, std::move(vb_descriptor));
437 auto ib_handle = resource_mgr.CreateIndexBuffer(
438 index_data.byte_count / index_data.stride, index_data.stride);
439 auto ibuf = resource_mgr.GetIndexBuffer(ib_handle).lock();
443 IndexBuffer::BufferDescriptor ib_descriptor(index_data.bytes,
444 index_data.byte_count);
446 ibuf->setBuffer(engine, std::move(ib_descriptor));
454 const filament::math::float3
min(geometry_aabb.minCorner().x,
455 geometry_aabb.minCorner().y,
456 geometry_aabb.minCorner().z);
457 const filament::math::float3
max(geometry_aabb.maxCorner().x,
458 geometry_aabb.maxCorner().y,
459 geometry_aabb.maxCorner().z);
469 : geometry_(geometry) {
474 "GPU resident triangle meshes are not currently supported for "
475 "visualization. Copying data to CPU.");
482 "Tensor triangle mesh vertices must have DType of Float32 not "
484 pts.GetDtype().ToString());
491 "Tensor triangle mesh normals must have DType of Float32 not "
493 normals.GetDtype().ToString());
501 "Tensor triangle mesh colors must have DType of Float32 not "
503 colors.GetDtype().ToString());
513 return RenderableManager::PrimitiveType::TRIANGLES;
526 const size_t n_vertices = need_duplicate_vertices ? indices.
GetLength() * 3
535 .vertexCount(uint32_t(n_vertices))
536 .attribute(VertexAttribute::POSITION, 0,
537 VertexBuffer::AttributeType::FLOAT3)
538 .normalized(VertexAttribute::COLOR)
539 .attribute(VertexAttribute::COLOR, 1,
540 VertexBuffer::AttributeType::FLOAT3)
541 .normalized(VertexAttribute::TANGENTS)
542 .attribute(VertexAttribute::TANGENTS, 2,
543 VertexBuffer::AttributeType::FLOAT4)
544 .attribute(VertexAttribute::CUSTOM0, 2,
545 VertexBuffer::AttributeType::FLOAT4)
546 .attribute(VertexAttribute::UV0, 3,
547 VertexBuffer::AttributeType::FLOAT2)
552 vb_handle = resource_mgr.AddVertexBuffer(vbuf);
558 const size_t vertex_array_size = n_vertices * 3 *
sizeof(float);
559 float* vertex_array =
static_cast<float*
>(malloc(vertex_array_size));
560 if (need_duplicate_vertices) {
562 {indices_64.Reshape({
static_cast<long>(n_vertices)})});
563 memcpy(vertex_array, dup_vertices.
GetDataPtr(), vertex_array_size);
565 memcpy(vertex_array,
points.GetDataPtr(), vertex_array_size);
567 VertexBuffer::BufferDescriptor pts_descriptor(
568 vertex_array, vertex_array_size,
570 vbuf->setBufferAt(engine, 0, std::move(pts_descriptor));
573 const size_t color_array_size = n_vertices * 3 *
sizeof(float);
574 float* color_array =
static_cast<float*
>(malloc(color_array_size));
576 if (need_duplicate_vertices) {
578 {indices_64.Reshape({
static_cast<long>(n_vertices)})});
579 memcpy(color_array, dup_colors.
GetDataPtr(), color_array_size);
591 memcpy(color_array, dup_colors.
GetDataPtr(), color_array_size);
593 for (
size_t i = 0; i < n_vertices * 3; ++i) {
594 color_array[i] = 0.5f;
597 VertexBuffer::BufferDescriptor color_descriptor(
598 color_array, color_array_size,
600 vbuf->setBufferAt(engine, 1, std::move(color_descriptor));
603 const size_t normal_array_size = n_vertices * 4 *
sizeof(float);
604 float* normal_array =
static_cast<float*
>(malloc(normal_array_size));
606 if (need_duplicate_vertices) {
608 {indices_64.Reshape({
static_cast<long>(n_vertices)})});
610 filament::geometry::SurfaceOrientation::Builder()
611 .vertexCount(n_vertices)
612 .normals(
reinterpret_cast<const math::float3*
>(
615 orientation->getQuats(
reinterpret_cast<math::quatf*
>(normal_array),
622 filament::geometry::SurfaceOrientation::Builder()
623 .vertexCount(n_vertices)
624 .normals(
reinterpret_cast<const math::float3*
>(
627 orientation->getQuats(
reinterpret_cast<math::quatf*
>(normal_array),
639 filament::geometry::SurfaceOrientation::Builder()
640 .vertexCount(n_vertices)
641 .normals(
reinterpret_cast<const math::float3*
>(
644 orientation->getQuats(
reinterpret_cast<math::quatf*
>(normal_array),
648 float* normal_ptr = normal_array;
649 for (
size_t i = 0; i < n_vertices; ++i) {
656 VertexBuffer::BufferDescriptor normals_descriptor(
657 normal_array, normal_array_size,
659 vbuf->setBufferAt(engine, 2, std::move(normals_descriptor));
662 const size_t uv_array_size = n_vertices * 2 *
sizeof(float);
663 float* uv_array =
static_cast<float*
>(malloc(uv_array_size));
665 if (need_duplicate_vertices) {
668 .IndexGet({indices_64.Reshape(
669 {
static_cast<long>(n_vertices)})});
670 memcpy(uv_array, dup_uvs.
GetDataPtr(), uv_array_size);
677 memcpy(uv_array, geometry_.
GetTriangleAttr(
"texture_uvs").GetDataPtr(),
680 memset(uv_array, 0x0, uv_array_size);
682 VertexBuffer::BufferDescriptor uv_descriptor(
684 vbuf->setBufferAt(engine, 3, std::move(uv_descriptor));
690 const uint32_t n_indices =
691 need_duplicate_vertices ? n_vertices : indices.GetLength() * 3;
692 const size_t n_bytes = n_indices *
sizeof(uint32_t);
693 auto* uint_indices =
static_cast<uint32_t*
>(malloc(n_bytes));
694 if (need_duplicate_vertices) {
695 std::iota(uint_indices, uint_indices + n_vertices, 0);
699 memcpy(uint_indices, indices_32.GetDataPtr(), n_bytes);
702 resource_mgr.CreateIndexBuffer(n_indices,
sizeof(uint32_t));
703 auto ibuf = resource_mgr.GetIndexBuffer(ib_handle).lock();
704 IndexBuffer::BufferDescriptor indices_descriptor(
706 ibuf->setBuffer(engine, std::move(indices_descriptor));
709 return std::make_tuple(vb_handle, ib_handle, downsampled_handle);
715 auto* min_bounds_float = min_bounds.
GetDataPtr<
float>();
716 auto* max_bounds_float = max_bounds.GetDataPtr<
float>();
718 const filament::math::float3 min_pt(
719 min_bounds_float[0], min_bounds_float[1], min_bounds_float[2]);
720 const filament::math::float3 max_pt(
721 max_bounds_float[0], max_bounds_float[1], max_bounds_float[2]);
724 aabb.set(min_pt, max_pt);
725 if (aabb.isEmpty()) {
726 const filament::math::float3
offset(0.1, 0.1, 0.1);
std::vector< Eigen::Vector2d > triangle_uvs_
List of uv coordinates per triangle.
bool hasColors() const override
Returns whether colors are enabled or not.
Eigen::Vector3d getVertice(size_t index) const
virtual ccBBox GetAxisAlignedBoundingBox() const override
Returns an axis-aligned bounding box of the geometry.
unsigned int getVerticeSize() const
Eigen::Vector3d getVertexColor(size_t index) const
bool hasNormals() const override
Returns whether normals are enabled or not.
virtual unsigned size() const override
Returns the number of triangles.
Eigen::Vector3i getTriangle(size_t index) const
Eigen::Vector3d getVertexNormal(size_t index) const
bool hasTriangleUvs() const
int64_t GetLength() const
Tensor IndexGet(const std::vector< Tensor > &index_tensors) const
Advanced indexing getter. This will always allocate a new Tensor.
static Tensor Empty(const SizeVector &shape, Dtype dtype, const Device &device=Device("CPU:0"))
Create a tensor with uninitialized values.
Tensor Slice(int64_t dim, int64_t start, int64_t stop, int64_t step=1) const
Tensor To(Dtype dtype, bool copy=false) const
A triangle mesh contains vertices and triangles.
bool HasTriangleNormals() const
core::Tensor & GetTriangleIndices()
core::Tensor & GetVertexNormals()
const TensorMap & GetVertexAttr() const
Getter for vertex_attr_ TensorMap. Used in Pybind.
core::Tensor GetMaxBound() const
bool HasVertexNormals() const
core::Tensor & GetVertexPositions()
bool HasTriangleColors() const
core::Tensor & GetTriangleNormals()
core::Tensor & GetVertexColors()
TriangleMesh To(const core::Device &device, bool copy=false) const
bool HasVertexAttr(const std::string &key) const
bool HasVertexColors() const
core::Tensor & GetTriangleColors()
bool HasTriangleAttr(const std::string &key) const
const TensorMap & GetTriangleAttr() const
Getter for triangle_attr_ TensorMap. Used in Pybind.
core::Tensor GetMinBound() const
static filament::Engine & GetInstance()
static FilamentResourceManager & GetResourceManager()
static void DeallocateBuffer(void *buffer, size_t size, void *user_ptr)
std::tuple< VertexBufferHandle, IndexBufferHandle, IndexBufferHandle > Buffers
filament::RenderableManager::PrimitiveType GetPrimitiveType() const override
filament::Box ComputeAABB() override
Buffers ConstructBuffers() override
TMeshBuffersBuilder(const t::geometry::TriangleMesh &geometry)
filament::RenderableManager::PrimitiveType GetPrimitiveType() const override
Buffers ConstructBuffers() override
filament::Box ComputeAABB() override
__host__ __device__ int2 abs(int2 v)
constexpr bool operator<(const optional< T > &x, const optional< T > &y)
REHandle< EntityType::IndexBuffer > IndexBufferHandle
Generic file read and write utility for python interface.
#define offsetof(STRUCTURE, FIELD)