Lagrange
mesh.impl.h
1/*
2 * Copyright 2021 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <igl/ray_mesh_intersect.h>
15#include <lagrange/attributes/attribute_utils.h>
16#include <lagrange/compute_tangent_bitangent.h>
17#include <lagrange/compute_vertex_normal.h>
18#include <lagrange/select_facets_in_frustum.h>
19#include <lagrange/ui/Entity.h>
20#include <lagrange/ui/types/Camera.h>
21#include <lagrange/ui/types/Color.h>
22#include <lagrange/ui/types/Frustum.h>
23#include <lagrange/ui/types/RayFacetHit.h>
24#include <lagrange/ui/types/VertexBuffer.h>
25#include <lagrange/ui/utils/math.h>
26#include <lagrange/ui/utils/objectid_viewport.h>
27#include <lagrange/utils/tbb.h>
28
29namespace lagrange {
30namespace ui {
31
32namespace detail {
33
35// Getters
37
38template <typename T>
39RowMajorMatrixXf eigen_convert_to_float(const T& input)
40{
41 return input.template cast<float>().eval();
42}
43
44template <typename T>
45RowMajorMatrixXi eigen_convert_to_int(const T& input)
46{
47 return input.template cast<int>().eval();
48}
49
50template <typename MeshType>
51size_t get_num_vertices(const MeshBase* mesh_base)
52{
53 return reinterpret_cast<const MeshType&>(*mesh_base).get_num_vertices();
54}
55template <typename MeshType>
56size_t get_num_facets(const MeshBase* mesh_base)
57{
58 return reinterpret_cast<const MeshType&>(*mesh_base).get_num_facets();
59}
60template <typename MeshType>
61size_t get_num_edges(const MeshBase* mesh_base)
62{
63 return reinterpret_cast<const MeshType&>(*mesh_base).get_num_edges();
64}
65
66template <typename MeshType>
67RowMajorMatrixXf get_mesh_vertices(const MeshBase* mesh_base)
68{
69 return reinterpret_cast<const MeshType&>(*mesh_base).get_vertices().template cast<float>();
70}
71
72
73template <typename MeshType>
74RowMajorMatrixXi get_mesh_facets(const MeshBase* mesh_base)
75{
76 return reinterpret_cast<const MeshType&>(*mesh_base).get_facets().template cast<int>();
77}
78
79template <typename MeshType>
80RowMajorMatrixXf get_mesh_vertex_attribute(const MeshBase* mesh_base, const std::string& name)
81{
82 return reinterpret_cast<const MeshType&>(*mesh_base)
83 .get_vertex_attribute(name)
84 .template cast<float>();
85}
86
87template <typename MeshType>
88RowMajorMatrixXf get_mesh_corner_attribute(const MeshBase* mesh_base, const std::string& name)
89{
90 return reinterpret_cast<const MeshType&>(*mesh_base)
91 .get_corner_attribute(name)
92 .template cast<float>();
93}
94
95template <typename MeshType>
96RowMajorMatrixXf get_mesh_facet_attribute(const MeshBase* mesh_base, const std::string& name)
97{
98 return reinterpret_cast<const MeshType&>(*mesh_base)
99 .get_facet_attribute(name)
100 .template cast<float>();
101}
102
103template <typename MeshType>
104RowMajorMatrixXf get_mesh_edge_attribute(const MeshBase* mesh_base, const std::string& name)
105{
106 return reinterpret_cast<const MeshType&>(*mesh_base)
107 .get_edge_attribute(name)
108 .template cast<float>();
109}
110
111
112template <typename MeshType>
113RowMajorMatrixXf
114get_mesh_attribute(const MeshBase* mesh_base, IndexingMode mode, const std::string& name)
115{
117 mode != lagrange::ui::IndexingMode::INDEXED,
118 "Indexed attribute not supported. Map to corner first.");
119
120 const auto& mesh = reinterpret_cast<const MeshType&>(*mesh_base);
121 switch (mode) {
122 case lagrange::ui::IndexingMode::VERTEX:
123 return mesh.get_vertex_attribute(name).template cast<float>();
124 case lagrange::ui::IndexingMode::EDGE:
125 return mesh.get_edge_attribute(name).template cast<float>();
126 case lagrange::ui::IndexingMode::FACE:
127 return mesh.get_facet_attribute(name).template cast<float>();
128 case lagrange::ui::IndexingMode::CORNER:
129 return mesh.get_corner_attribute(name).template cast<float>();
130 default: break;
131 }
132 return RowMajorMatrixXf();
133}
134
135
136template <typename MeshType>
137std::pair<Eigen::VectorXf, Eigen::VectorXf>
138get_mesh_attribute_range(const MeshBase* mesh_base, IndexingMode mode, const std::string& name)
139{
140 using AttributeArray = typename MeshType::AttributeArray;
141
142 const AttributeArray* aa = nullptr;
143 const auto& mesh = reinterpret_cast<const MeshType&>(*mesh_base);
144
145 switch (mode) {
146 case lagrange::ui::IndexingMode::VERTEX: aa = &mesh.get_vertex_attribute(name); break;
147 case lagrange::ui::IndexingMode::EDGE: aa = &mesh.get_edge_attribute(name); break;
148 case lagrange::ui::IndexingMode::FACE: aa = &mesh.get_facet_attribute(name); break;
149 case lagrange::ui::IndexingMode::CORNER: aa = &mesh.get_corner_attribute(name); break;
150 default: break;
151 }
152
153 la_runtime_assert(aa != nullptr);
154
155 return {
156 aa->colwise().minCoeff().transpose().template cast<float>().eval(),
157 aa->colwise().maxCoeff().transpose().template cast<float>().eval()};
158}
159
160template <typename MeshType>
161AABB get_mesh_bounds(const MeshBase* mesh_base)
162{
163 const auto& mesh = reinterpret_cast<const MeshType&>(*mesh_base);
164 if (mesh.get_num_vertices() == 0) return AABB();
165
166 const auto& V = mesh.get_vertices();
167 return AABB(
168 V.colwise().minCoeff().template cast<float>(),
169 V.colwise().maxCoeff().template cast<float>());
170}
171
173// Ensure existence of mesh attributes for rendering
175
176template <typename MeshType>
177void ensure_uv(MeshBase* d)
178{
179 auto& mesh = reinterpret_cast<MeshType&>(*d);
180 if (!mesh.has_corner_attribute("uv")) {
181 if (mesh.has_vertex_attribute("uv")) {
182 map_vertex_attribute_to_corner_attribute(mesh, "uv");
183 } else if (mesh.has_indexed_attribute("uv")) {
184 map_indexed_attribute_to_corner_attribute(mesh, "uv");
185 } else {
186 // No UV
187 }
188 }
189}
190
191template <typename MeshType>
192void ensure_normal(MeshBase* d)
193{
194 auto& mesh = reinterpret_cast<MeshType&>(*d);
195 if (!mesh.has_corner_attribute("normal")) {
196 if (mesh.has_vertex_attribute("normal")) {
197 map_vertex_attribute_to_corner_attribute(mesh, "normal");
198 } else if (mesh.has_indexed_attribute("normal")) {
199 map_indexed_attribute_to_corner_attribute(mesh, "normal");
200 } else {
201 lagrange::compute_vertex_normal(mesh, PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM);
202 map_vertex_attribute_to_corner_attribute(mesh, "normal");
203 }
204 }
205}
206
207template <typename MeshType>
208void ensure_tangent_bitangent(MeshBase* d)
209{
210 auto& mesh = reinterpret_cast<MeshType&>(*d);
211
212 if (!mesh.has_corner_attribute("tangent") || !mesh.has_corner_attribute("bitangent")) {
213 if (mesh.has_vertex_attribute("tangent")) {
214 map_vertex_attribute_to_corner_attribute(mesh, "tangent");
215 }
216 if (mesh.has_vertex_attribute("bitangent")) {
217 map_vertex_attribute_to_corner_attribute(mesh, "bitangent");
218 }
219
220 // Check again
221 if (!mesh.has_corner_attribute("tangent") || !mesh.has_corner_attribute("bitangent")) {
222 if (mesh.has_corner_attribute("uv")) {
223 compute_corner_tangent_bitangent(mesh);
224 } else {
225 // No uvs -> no tangent nor bitangent
226 }
227 }
228 }
229}
230
231template <typename MeshType>
232void ensure_is_selected_attribute(MeshBase* d)
233{
234 auto& mesh = reinterpret_cast<MeshType&>(*d);
235
236 const auto attrib_name = "is_selected";
237 using AttributeArray = typename MeshType::AttributeArray;
238
239 if (!mesh.has_corner_attribute(attrib_name)) {
240 mesh.add_corner_attribute(attrib_name);
241 mesh.import_corner_attribute(
242 attrib_name,
243 AttributeArray::Zero(mesh.get_num_facets() * mesh.get_vertex_per_facet(), 1));
244 }
245
246 if (!mesh.has_facet_attribute(attrib_name)) {
247 mesh.add_facet_attribute(attrib_name);
248 mesh.import_facet_attribute(attrib_name, AttributeArray::Zero(mesh.get_num_facets(), 1));
249 }
250
251 if (mesh.is_edge_data_initialized() && !mesh.has_edge_attribute(attrib_name)) {
252 mesh.add_edge_attribute(attrib_name);
253 mesh.import_edge_attribute(attrib_name, AttributeArray::Zero(mesh.get_num_edges(), 1));
254 }
255
256 if (!mesh.has_vertex_attribute(attrib_name)) {
257 mesh.add_vertex_attribute(attrib_name);
258 mesh.import_vertex_attribute(attrib_name, AttributeArray::Zero(mesh.get_num_vertices(), 1));
259 }
260}
261
262template <typename MeshType>
263void map_indexed_attribute_to_corner_attribute(MeshBase* d, const std::string& name)
264{
265 auto& mesh = reinterpret_cast<MeshType&>(*d);
266 lagrange::map_indexed_attribute_to_corner_attribute(mesh, name);
267}
268
269template <typename MeshType>
270void map_corner_attribute_to_vertex_attribute(MeshBase* d, const std::string& name)
271{
272 auto& mesh = reinterpret_cast<MeshType&>(*d);
273 lagrange::map_corner_attribute_to_vertex_attribute(mesh, name);
274}
275
277// Mesh to GPU upload
279
280
281template <typename FacetArray>
282void upload_facets(const FacetArray& facets, GPUBuffer* gpu)
283{
284 static_assert(sizeof(typename FacetArray::Scalar) == sizeof(unsigned int), "Must be u/int32");
285 gpu->vbo().upload(
286 GLuint(facets.size() * sizeof(unsigned int)),
287 (const uint8_t*)facets.data(),
288 GLsizei(facets.rows()),
289 true,
290 GL_UNSIGNED_INT);
291}
292
293template <typename MeshType>
294void upload_mesh_triangles(const MeshBase* mesh_base, GPUBuffer* gpu)
295{
296 const auto& mesh = reinterpret_cast<const MeshType&>(*mesh_base);
297 la_runtime_assert(mesh.get_facets().cols() == 3, "Triangulate the mesh first");
298
299 auto& facets = mesh.get_facets();
300 upload_facets(facets, gpu);
301}
302
303
304template <typename T>
305std::shared_ptr<GPUBuffer> create_gpubuffer_and_upload(T&& data)
306{
307 auto gpubuf = std::make_shared<GPUBuffer>();
308 gpubuf->vbo().upload(std::move(data));
309 return gpubuf;
310}
311
312template <typename T>
313std::shared_ptr<GPUBuffer> create_gpubuffer_and_upload(const T& data)
314{
315 auto gpubuf = std::make_shared<GPUBuffer>();
316 gpubuf->vbo().upload(data);
317 return gpubuf;
318}
319
320template <typename MeshType>
321void upload_mesh_vertex_attribute(const MeshBase* d, const RowMajorMatrixXf* data, GPUBuffer* gpu)
322{
323 auto& m = reinterpret_cast<const MeshType&>(*d);
324 la_runtime_assert(data->rows() == m.get_num_vertices());
325 RowMajorMatrixXf flattened = RowMajorMatrixXf(m.get_num_facets() * 3, data->cols());
326
327 const auto& F = m.get_facets();
328 for (auto fi = 0; fi < m.get_num_facets(); fi++) {
329 flattened.row(3 * fi + 0) = data->row(F(fi, 0));
330 flattened.row(3 * fi + 1) = data->row(F(fi, 1));
331 flattened.row(3 * fi + 2) = data->row(F(fi, 2));
332 }
333
334 (*gpu).vbo().upload(std::move(flattened));
335}
336
337template <typename MeshType>
338void upload_mesh_corner_attribute(const MeshBase* d, const RowMajorMatrixXf* data, GPUBuffer* gpu)
339{
340 auto& m = reinterpret_cast<const MeshType&>(*d);
341 la_runtime_assert(data->rows() == m.get_num_facets() * 3);
342 (*gpu).vbo().upload(*data);
343}
344
345template <typename MeshType>
346void upload_mesh_facet_attribute(const MeshBase* d, const RowMajorMatrixXf* data, GPUBuffer* gpu)
347{
348 auto& m = reinterpret_cast<const MeshType&>(*d);
349 la_runtime_assert(data->rows() == m.get_num_facets());
350
351 RowMajorMatrixXf flattened = RowMajorMatrixXf(m.get_num_facets() * 3, data->cols());
352
353 for (auto i = 0; i < data->rows(); i++) {
354 flattened.row(3 * i + 0) = data->row(i);
355 flattened.row(3 * i + 1) = data->row(i);
356 flattened.row(3 * i + 2) = data->row(i);
357 }
358
359 (*gpu).vbo().upload(std::move(flattened));
360}
361
362template <typename MeshType>
363void upload_mesh_edge_attribute(const MeshBase* d, const RowMajorMatrixXf* data, GPUBuffer* gpu)
364{
365 const auto& m = reinterpret_cast<const MeshType&>(*d);
366 la_runtime_assert(m.is_edge_data_initialized(), "Edge data (new) not initialized");
367 la_runtime_assert(data->rows() == m.get_num_edges());
368
369 const auto& F = m.get_facets();
370 const auto per_facet = m.get_vertex_per_facet();
371
372 RowMajorMatrixXf flattened = RowMajorMatrixXf(m.get_num_facets() * per_facet, data->cols());
373
374 // For each flattened triangle
375 for (auto i = 0; i < F.rows(); i++) {
376 // For each of its edges
377 for (auto k = 0; k < per_facet; k++) {
378 const auto ei = m.get_edge(i, k);
379 flattened.row(per_facet * i + k) = data->row(ei);
380 }
381 }
382
383 (*gpu).vbo().upload(std::move(flattened));
384}
385
386template <typename MeshType>
387void upload_mesh_vertices(const MeshBase* mesh_base, GPUBuffer* gpu)
388{
389 // TODO template for 2D
390 auto& m = reinterpret_cast<const MeshType&>(*mesh_base);
391 auto& data = m.get_vertices();
392
393 RowMajorMatrixXf flattened = RowMajorMatrixXf(m.get_num_facets() * 3, data.cols());
394
395 const auto& F = m.get_facets();
396 for (auto fi = 0; fi < m.get_num_facets(); fi++) {
397 flattened.row(3 * fi + 0) = data.row(F(fi, 0)).template cast<float>();
398 flattened.row(3 * fi + 1) = data.row(F(fi, 1)).template cast<float>();
399 flattened.row(3 * fi + 2) = data.row(F(fi, 2)).template cast<float>();
400 }
401
402 (*gpu).vbo().upload(std::move(flattened));
403}
404
405template <typename MeshType>
406std::unordered_map<entt::id_type, std::shared_ptr<GPUBuffer>> upload_submesh_indices(
407 const MeshBase* mesh_base,
408 const std::string& facet_attrib_name)
409{
410 auto& m = reinterpret_cast<const MeshType&>(*mesh_base);
411
412 const auto& sub_ids = m.get_facet_attribute(facet_attrib_name);
413
414 using FacetArray = typename MeshType::FacetArray;
415
416 std::unordered_map<entt::id_type, std::shared_ptr<GPUBuffer>> result;
417 std::unordered_map<entt::id_type, size_t> sub_counts;
418 std::unordered_map<entt::id_type, FacetArray> submesh_triangles;
419
420 // Count submeshes and number of triangles per submesh
421 for (auto fi = 0; fi < m.get_num_facets(); fi++) {
422 auto id = entt::id_type(sub_ids(fi, 0));
423 auto it = sub_counts.find(id);
424 if (it == sub_counts.end())
425 sub_counts.insert({id, 1});
426 else
427 it->second++;
428 }
429
430 // Allocate submesh index arrays
431 for (auto& it : sub_counts) {
432 submesh_triangles.insert({it.first, FacetArray(it.second, 3)});
433 }
434
435 // Go in reverse, decrementing the counter
436 for (auto fi = m.get_num_facets() - 1; fi >= 0; fi--) {
437 auto id = entt::id_type(sub_ids(fi, 0));
438 auto& counter = sub_counts.at(id);
439 auto& triangles = submesh_triangles.at(id);
440 triangles(counter - 1, 0) = 3 * fi + 0;
441 triangles(counter - 1, 1) = 3 * fi + 1;
442 triangles(counter - 1, 2) = 3 * fi + 2;
443 counter--;
444 }
445#ifdef _DEBUG
446 for (auto& it : sub_counts) {
447 assert(it.second == 0);
448 }
449#endif
450
451 for (auto& it : submesh_triangles) {
452 auto buf = std::make_shared<GPUBuffer>(GL_ELEMENT_ARRAY_BUFFER);
453 upload_facets(it.second, buf.get());
454 result.insert({it.first, std::move(buf)});
455 }
456
457
458 return result;
459}
460
461
463// Has attribute
465
466template <typename MeshType>
467bool has_mesh_vertex_attribute(const MeshBase* d, const std::string& name)
468{
469 return reinterpret_cast<const MeshType&>(*d).has_vertex_attribute(name);
470}
471template <typename MeshType>
472bool has_mesh_corner_attribute(const MeshBase* d, const std::string& name)
473{
474 return reinterpret_cast<const MeshType&>(*d).has_corner_attribute(name);
475}
476template <typename MeshType>
477bool has_mesh_facet_attribute(const MeshBase* d, const std::string& name)
478{
479 return reinterpret_cast<const MeshType&>(*d).has_facet_attribute(name);
480}
481template <typename MeshType>
482bool has_mesh_edge_attribute(const MeshBase* d, const std::string& name)
483{
484 return reinterpret_cast<const MeshType&>(*d).has_edge_attribute(name);
485}
486template <typename MeshType>
487bool has_mesh_indexed_attribute(const MeshBase* d, const std::string& name)
488{
489 return reinterpret_cast<const MeshType&>(*d).has_indexed_attribute(name);
490}
491
493// Picking
495
496template <typename MeshType>
497bool intersect_ray(
498 const MeshBase* mesh_base,
499 const Eigen::Vector3f& origin,
500 const Eigen::Vector3f& dir,
501 RayFacetHit* out)
502{
503 auto& m = reinterpret_cast<const MeshType&>(*mesh_base);
504 using Scalar = typename MeshType::Scalar;
505
506
507 igl::Hit ihit;
508 bool res = igl::ray_mesh_intersect(
509 origin.cast<Scalar>(),
510 dir.cast<Scalar>(),
511 m.get_vertices(),
512 m.get_facets(),
513 ihit);
514
515 if (!res) return false;
516
517 out->facet_id = ihit.id;
518 out->t = ihit.t;
519 out->barycentric = Eigen::Vector3f(1.0f - ihit.u - ihit.v, ihit.u, ihit.v);
520 return true;
521}
522
523
524template <typename MeshType>
525bool select_facets_in_frustum(
526 MeshBase* mesh_base,
527 SelectionBehavior /*sel_behavior*/,
528 const Frustum* frustum_ptr)
529{
530 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
531 const auto& frustum = *frustum_ptr;
532 using Scalar = typename MeshType::Scalar;
533 using Point = Eigen::Matrix<Scalar, 3, 1>;
534
535
536 // Facet attribute
537 return lagrange::select_facets_in_frustum<MeshType, Point>(
538 mesh,
539 frustum.planes[FRUSTUM_LEFT].cast<Scalar>().normal().eval(),
540 frustum.planes[FRUSTUM_LEFT].cast<Scalar>().projection(Point::Zero()),
541 frustum.planes[FRUSTUM_BOTTOM].cast<Scalar>().normal().eval(),
542 frustum.planes[FRUSTUM_BOTTOM].cast<Scalar>().projection(Point::Zero()),
543 frustum.planes[FRUSTUM_RIGHT].cast<Scalar>().normal().eval(),
544 frustum.planes[FRUSTUM_RIGHT].cast<Scalar>().projection(Point::Zero()),
545 frustum.planes[FRUSTUM_TOP].cast<Scalar>().normal().eval(),
546 frustum.planes[FRUSTUM_TOP].cast<Scalar>().projection(Point::Zero()));
547}
548
549template <typename MeshType>
550void select_vertices_in_frustum(
551 MeshBase* mesh_base,
552 SelectionBehavior sel_behavior,
553 const Frustum* frustum_ptr)
554{
555 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
556 const auto& frustum = *frustum_ptr;
557
558 static_assert(MeshTrait<MeshType>::is_mesh(), "Input is not a mesh.");
559 using AttributeArray = typename MeshType::AttributeArray;
560 using Scalar = typename MeshType::Scalar;
561 using Index = typename MeshType::Index;
562
563 const auto num_vertices = mesh.get_num_vertices();
564 const auto& vertices = mesh.get_vertices();
565
566 AttributeArray attr;
567
568 if (!mesh.has_vertex_attribute("is_selected")) {
569 mesh.add_vertex_attribute("is_selected");
570 attr = AttributeArray(num_vertices, 1);
571 } else {
572 mesh.export_vertex_attribute("is_selected", attr);
573 la_runtime_assert(attr.rows() == num_vertices);
574 }
575
576
577 if (sel_behavior == SelectionBehavior::SET) {
578 attr.setZero();
579 }
580 using Scalar = typename MeshType::Scalar;
581 const Scalar value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
582
583
584 tbb::parallel_for(
585 tbb::blocked_range<Index>(0, num_vertices),
586 [&value, &attr, &frustum, &vertices](const tbb::blocked_range<Index>& tbb_range) {
587 for (auto vi = tbb_range.begin(); vi != tbb_range.end(); vi++) {
588 if (tbb_utils::is_cancelled()) break;
589 if (frustum.contains(vertices.row(vi).template cast<float>())) {
590 attr(vi, 0) = value;
591 }
592 }
593 });
594
595 mesh.import_vertex_attribute("is_selected", attr);
596}
597
598template <typename MeshType>
599void select_edges_in_frustum(
600 MeshBase* /*mesh_base*/,
601 SelectionBehavior /*sel_behavior*/,
602 const Frustum* /*frustum_ptr*/)
603{
604 la_runtime_assert(false, "not implemented yet");
605}
606
607
608template <typename MeshType>
609void propagate_corner_selection(MeshBase* mesh_base, const std::string& attrib_name)
610{
611 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
612
613 static_assert(MeshTrait<MeshType>::is_mesh(), "MeshType is not a mesh");
614
615 using Index = typename MeshType::Index;
616 la_runtime_assert(mesh.has_corner_attribute(attrib_name));
617
618 const Index num_facets = mesh.get_num_facets();
619 const Index vertex_per_facet = mesh.get_vertex_per_facet();
620
621 const auto& facets = mesh.get_facets();
622
623 {
624 typename MeshType::AttributeArray corner_attrib;
625 mesh.export_corner_attribute(attrib_name, corner_attrib);
626
627 typename MeshType::AttributeArray vertex_attrib;
628 mesh.export_vertex_attribute(attrib_name, vertex_attrib);
629
630 vertex_attrib.setZero();
631
632 // TODO: TBB Parallelize
633
634 // Corner to vertex
635 for (Index i = 0; i < num_facets; i++) {
636 for (Index j = 0; j < vertex_per_facet; j++) {
637 if (corner_attrib(i * vertex_per_facet + j) != 0.0f) {
638 vertex_attrib(facets(i, j)) = 1.0f;
639 }
640 }
641 }
642
643 // Vertex to corner
644 for (Index i = 0; i < num_facets; i++) {
645 for (Index j = 0; j < vertex_per_facet; j++) {
646 if (vertex_attrib(facets(i, j)) != 0.0f) {
647 corner_attrib(i * vertex_per_facet + j) = 1.0f;
648 }
649 }
650 }
651
652 mesh.import_vertex_attribute(attrib_name, vertex_attrib);
653 mesh.import_corner_attribute(attrib_name, corner_attrib);
654 }
655}
656
657template <typename MeshType>
658void propagate_vertex_selection(MeshBase* mesh_base, const std::string& attrib_name)
659{
660 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
661 static_assert(MeshTrait<MeshType>::is_mesh(), "MeshType is not a mesh");
662
663 using Index = typename MeshType::Index;
664 la_runtime_assert(mesh.has_corner_attribute(attrib_name));
665 la_runtime_assert(mesh.has_vertex_attribute(attrib_name));
666
667 const Index num_facets = mesh.get_num_facets();
668 const Index vertex_per_facet = mesh.get_vertex_per_facet();
669
670 const auto& facets = mesh.get_facets();
671
672 typename MeshType::AttributeArray corner_attrib;
673 mesh.export_corner_attribute(attrib_name, corner_attrib);
674
675 const typename MeshType::AttributeArray& vertex_attrib = mesh.get_vertex_attribute(attrib_name);
676
677 tbb::parallel_for(
678 tbb::blocked_range<Index>(0, num_facets),
679 [&](const tbb::blocked_range<Index>& tbb_range) {
680 for (auto fi = tbb_range.begin(); fi != tbb_range.end(); fi++) {
681 if (tbb_utils::is_cancelled()) break;
682
683 for (Index j = 0; j < vertex_per_facet; j++) {
684 if (vertex_attrib(facets(fi, j)) != 0.0f) {
685 corner_attrib(fi * vertex_per_facet + j) = 1.0f;
686 } else {
687 corner_attrib(fi * vertex_per_facet + j) = 0.0f;
688 }
689 }
690 }
691 });
692
693 mesh.import_corner_attribute(attrib_name, corner_attrib);
694}
695
696template <typename MeshType>
697void propagate_facet_selection(MeshBase* mesh_base, const std::string& attrib_name)
698{
699 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
700
701 // Convert to vertex attribute
702 const auto per_facet = mesh.get_vertex_per_facet();
703 const auto& facet_attr = mesh.get_facet_attribute(attrib_name);
704
705 using AttributeArray = typename MeshType::AttributeArray;
706
707 AttributeArray vertex_attr;
708 mesh.export_vertex_attribute(attrib_name, vertex_attr);
709 vertex_attr.setZero();
710
711 const auto& F = mesh.get_facets();
712
713 // TODO: TBB paralellize
714 for (auto fi = 0; fi < F.rows(); fi++) {
715 for (auto j = 0; j < per_facet; j++) {
716 auto val = facet_attr(fi);
717 if (val > 0.0f) {
718 vertex_attr(F(fi, j)) = val;
719 }
720 }
721 }
722 mesh.import_vertex_attribute(attrib_name, vertex_attr);
723
724 // Map to corner for visualization
725 lagrange::map_vertex_attribute_to_corner_attribute(mesh, attrib_name);
726}
727
728
733template <typename MeshType>
734void combine_vertex_and_corner_selection(MeshBase* mesh_base, const std::string& attrib_name)
735{
736 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
737
738 using AttribArray = typename MeshType::AttributeArray;
739
740 const auto num_facets = mesh.get_num_facets();
741 const auto vertex_per_facet = mesh.get_vertex_per_facet();
742 const auto& facets = mesh.get_facets();
743
744 const AttribArray& vertex_attrib = mesh.get_vertex_attribute(attrib_name);
745
746 AttribArray corner_attrib;
747 mesh.export_corner_attribute(attrib_name, corner_attrib);
748
749 using Index = typename MeshType::Index;
750 using Scalar = typename MeshType::Scalar;
751
752 tbb::parallel_for(
753 tbb::blocked_range<Index>(0, num_facets),
754 [&](const tbb::blocked_range<Index>& tbb_range) {
755 for (auto fi = tbb_range.begin(); fi != tbb_range.end(); fi++) {
756 if (tbb_utils::is_cancelled()) break;
757 for (Index j = 0; j < vertex_per_facet; j++) {
758 auto& corner_val = corner_attrib(fi * vertex_per_facet + j);
759 if (vertex_attrib(facets(fi, j)) != Scalar(0) && corner_val != Scalar(0)) {
760 corner_val = Scalar(1);
761 } else {
762 corner_val = Scalar(0);
763 }
764 }
765 }
766 });
767
768 mesh.import_corner_attribute(attrib_name, corner_attrib);
769}
770
771template <typename MeshType>
772void select_facets_by_color(
773 MeshBase* mesh_base,
774 const std::string& attrib_name,
775 SelectionBehavior sel_behavior,
776 const unsigned char* color_bytes,
777 size_t colors_byte_size)
778{
779 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
780
781 using Attr = typename MeshType::AttributeArray;
782 Attr attrib;
783 mesh.export_facet_attribute(attrib_name, attrib);
784
785 if (sel_behavior == SelectionBehavior::SET) {
786 attrib.setZero();
787 }
788 using Scalar = typename MeshType::Scalar;
789 const auto value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
790
791 const size_t pixel_size = 4;
792 for (size_t i = 0; i < colors_byte_size / pixel_size; i++) {
793 const auto id = color_to_id(
794 color_bytes[pixel_size * i + 0],
795 color_bytes[pixel_size * i + 1],
796 color_bytes[pixel_size * i + 2]);
797 if (is_id_background(id)) continue;
798 attrib(id) = value;
799 }
800
801 mesh.import_facet_attribute(attrib_name, attrib);
802}
803
804template <typename MeshType>
805void select_edges_by_color(
806 MeshBase* mesh_base,
807 const std::string& attrib_name,
808 SelectionBehavior sel_behavior,
809 const unsigned char* color_bytes,
810 size_t colors_byte_size)
811{
812 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
813
814 using Attr = typename MeshType::AttributeArray;
815 Attr attrib;
816 mesh.export_corner_attribute(attrib_name, attrib);
817
818
819 if (sel_behavior == SelectionBehavior::SET) {
820 attrib.setZero();
821 }
822 using Scalar = typename MeshType::Scalar;
823 const auto value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
824
825 const size_t pixel_size = 4;
826 for (size_t i = 0; i < colors_byte_size / pixel_size; i++) {
827 const auto id = color_to_id(
828 color_bytes[pixel_size * i + 0],
829 color_bytes[pixel_size * i + 1],
830 color_bytes[pixel_size * i + 2]);
831 if (is_id_background(id)) continue;
832
833 const auto face_id = id / 3;
834 const auto edge_id = id % 3;
835 attrib(face_id * 3 + (edge_id + 1) % 3) = value;
836 attrib(face_id * 3 + (edge_id + 2) % 3) = value;
837 }
838 mesh.import_corner_attribute(attrib_name, attrib);
839}
840
841template <typename MeshType>
842void select_vertices_by_color(
843 MeshBase* mesh_base,
844 const std::string& attrib_name,
845 SelectionBehavior sel_behavior,
846 const unsigned char* color_bytes,
847 size_t colors_byte_size)
848{
849 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
850
851 using Attr = typename MeshType::AttributeArray;
852 Attr attrib;
853 mesh.export_corner_attribute(attrib_name, attrib);
854
855 if (sel_behavior == SelectionBehavior::SET) {
856 attrib.setZero();
857 }
858 using Scalar = typename MeshType::Scalar;
859 const auto value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
860
861
862 const size_t pixel_size = 4;
863 for (size_t i = 0; i < colors_byte_size / pixel_size; i++) {
864 const auto id = color_to_id(
865 color_bytes[pixel_size * i + 0],
866 color_bytes[pixel_size * i + 1],
867 color_bytes[pixel_size * i + 2]);
868 if (is_id_background(id)) continue;
869 attrib(id) = value;
870 }
871 mesh.import_corner_attribute(attrib_name, attrib);
872}
873
874
875template <typename MeshType>
876void select_facets(
877 MeshBase* mesh_base,
878 SelectionBehavior sel_behavior,
879 const std::vector<int>* facet_indices)
880{
881 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
882
883 const auto attrib_name = "is_selected";
884 using Attr = typename MeshType::AttributeArray;
885 Attr attrib;
886 mesh.export_facet_attribute(attrib_name, attrib);
887
888 if (sel_behavior == SelectionBehavior::SET) {
889 attrib.setZero();
890 }
891
892 using Scalar = typename MeshType::Scalar;
893 const auto value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
894
895 for (auto i : (*facet_indices)) {
896 attrib(i, 0) = value;
897 }
898
899 mesh.import_facet_attribute(attrib_name, attrib);
900}
901
902
903template <typename MeshType>
904void filter_closest_vertex(
905 MeshBase* mesh_base,
906 const std::string& attrib_name,
907 SelectionBehavior sel_behavior,
908 const Camera& camera,
909 const Eigen::Vector2i& viewport_pos)
910{
911 auto& mesh = reinterpret_cast<MeshType&>(*mesh_base);
912 using AttribArray = typename MeshType::AttributeArray;
913
914 const auto num_vertices = mesh.get_num_vertices();
915 const auto& vertices = mesh.get_vertices();
916
917 AttribArray vertex_attrib;
918 mesh.export_vertex_attribute(attrib_name, vertex_attrib);
919
920 using Index = typename MeshType::Index;
921 using Scalar = typename MeshType::Scalar;
922
923 struct LocalBuffer
924 {
925 int screen_diff = std::numeric_limits<int>::max();
926 float min_depth = std::numeric_limits<float>::max();
927 Index min_vi = lagrange::invalid<Index>();
928 std::vector<Index> equivalence = {};
929 };
930
931 tbb::enumerable_thread_specific<LocalBuffer> temp_vars;
932
933 tbb::parallel_for(
934 tbb::blocked_range<Index>(0, num_vertices),
935 [&](const tbb::blocked_range<Index>& tbb_range) {
936 auto& min_screen_diff = temp_vars.local().screen_diff;
937 auto& min_depth = temp_vars.local().min_depth;
938 auto& min_vi = temp_vars.local().min_vi;
939 auto& equiv = temp_vars.local().equivalence;
940
941 for (auto vi = tbb_range.begin(); vi != tbb_range.end(); vi++) {
942 if (tbb_utils::is_cancelled()) break;
943
944 if (vertex_attrib(vi) == 0.0f) continue;
945
946 const auto proj =
947 camera.project_with_depth(vertices.row(vi).template cast<float>());
948 const auto diff =
949 (Eigen::Vector2i(int(proj.x()), int(camera.get_window_height() - proj.y())) -
950 viewport_pos)
951 .squaredNorm();
952
953 if (diff == min_screen_diff && proj.z() == min_depth) {
954 equiv.push_back(vi);
955 } else if (
956 proj.z() < min_depth || (proj.z() == min_depth && diff < min_screen_diff)) {
957 min_screen_diff = diff;
958 min_depth = proj.z();
959 min_vi = vi;
960 equiv.clear();
961 }
962 }
963 });
964
965
966 {
967 LocalBuffer final_buffer;
968 for (auto& var : temp_vars) {
969 if (var.min_vi == lagrange::invalid<Index>()) continue;
970
971 if (var.screen_diff == final_buffer.screen_diff &&
972 var.min_depth == final_buffer.min_depth) {
973 final_buffer.equivalence.push_back(var.min_vi);
974 for (auto e : var.equivalence) {
975 final_buffer.equivalence.push_back(e);
976 }
977 } else if (
978 var.min_depth < final_buffer.min_depth ||
979 (var.screen_diff < final_buffer.screen_diff &&
980 var.min_depth == final_buffer.min_depth)) {
981 final_buffer.screen_diff = var.screen_diff;
982 final_buffer.min_depth = var.min_depth;
983 final_buffer.min_vi = var.min_vi;
984 final_buffer.equivalence.clear();
985 }
986 }
987
988 if (sel_behavior == SelectionBehavior::SET) {
989 vertex_attrib.setZero();
990 }
991
992 const auto value = (sel_behavior != SelectionBehavior::ERASE) ? Scalar(1) : Scalar(0);
993
994 if (final_buffer.min_vi != lagrange::invalid<Index>()) {
995 vertex_attrib(final_buffer.min_vi, 0) = value;
996 for (auto equiv_vi : final_buffer.equivalence) {
997 vertex_attrib(equiv_vi, 0) = value;
998 }
999 }
1000 }
1001
1002
1003 mesh.import_vertex_attribute(attrib_name, vertex_attrib);
1004}
1005
1006
1007} // namespace detail
1008
1009
1010template <typename MeshType>
1011void register_mesh_type(
1012 [[maybe_unused]] const std::string& display_name = entt::type_id<MeshType>().name().data())
1013{
1014 using namespace entt::literals;
1015
1016 // Register MeshType
1017 entt::meta<MeshType>().template base<lagrange::MeshBase>();
1018
1019 // Register conversion functions
1020 using VertexArray = typename MeshType::VertexArray;
1021
1022 entt::meta<RowMajorMatrixXf>().template ctor<&detail::eigen_convert_to_float<VertexArray>>();
1023
1024 // Getters
1025 entt::meta<MeshType>().template func<&detail::get_num_vertices<MeshType>>(
1026 "get_num_vertices"_hs);
1027 entt::meta<MeshType>().template func<&detail::get_num_edges<MeshType>>("get_num_edges"_hs);
1028 entt::meta<MeshType>().template func<&detail::get_num_facets<MeshType>>("get_num_facets"_hs);
1029
1030 entt::meta<MeshType>().template func<&detail::get_mesh_vertices<MeshType>>(
1031 "get_mesh_vertices"_hs);
1032
1033 entt::meta<MeshType>().template func<&detail::get_mesh_facets<MeshType>>("get_mesh_facets"_hs);
1034 entt::meta<MeshType>().template func<&detail::get_mesh_vertex_attribute<MeshType>>(
1035 "get_mesh_vertex_attribute"_hs);
1036 entt::meta<MeshType>().template func<&detail::get_mesh_corner_attribute<MeshType>>(
1037 "get_mesh_corner_attribute"_hs);
1038 entt::meta<MeshType>().template func<&detail::get_mesh_facet_attribute<MeshType>>(
1039 "get_mesh_facet_attribute"_hs);
1040 entt::meta<MeshType>().template func<&detail::get_mesh_edge_attribute<MeshType>>(
1041 "get_mesh_edge_attribute"_hs);
1042 entt::meta<MeshType>().template func<&detail::get_mesh_attribute<MeshType>>(
1043 "get_mesh_attribute"_hs);
1044
1045 entt::meta<MeshType>().template func<&detail::get_mesh_attribute_range<MeshType>>(
1046 "get_mesh_attribute_range"_hs);
1047
1048 entt::meta<MeshType>().template func<&detail::get_mesh_bounds<MeshType>>("get_mesh_bounds"_hs);
1049
1050
1051 // Ensure attribs
1052 entt::meta<MeshType>().template func<&detail::ensure_uv<MeshType>>("ensure_uv"_hs);
1053 entt::meta<MeshType>().template func<&detail::ensure_normal<MeshType>>("ensure_normal"_hs);
1054 entt::meta<MeshType>().template func<&detail::ensure_tangent_bitangent<MeshType>>(
1055 "ensure_tangent_bitangent"_hs);
1056 entt::meta<MeshType>().template func<&detail::ensure_is_selected_attribute<MeshType>>(
1057 "ensure_is_selected_attribute"_hs);
1058 entt::meta<MeshType>()
1059 .template func<&detail::map_indexed_attribute_to_corner_attribute<MeshType>>(
1060 "map_indexed_attribute_to_corner_attribute"_hs);
1061 entt::meta<MeshType>()
1062 .template func<&detail::map_corner_attribute_to_vertex_attribute<MeshType>>(
1063 "map_corner_attribute_to_vertex_attribute"_hs);
1064
1065
1066 // Mesh to GPU
1067 entt::meta<MeshType>().template func<&detail::upload_mesh_vertices<MeshType>>(
1068 "upload_mesh_vertices"_hs);
1069 entt::meta<MeshType>().template func<&detail::upload_mesh_triangles<MeshType>>(
1070 "upload_mesh_triangles"_hs);
1071 entt::meta<MeshType>().template func<&detail::upload_mesh_vertex_attribute<MeshType>>(
1072 "upload_mesh_vertex_attribute"_hs);
1073 entt::meta<MeshType>().template func<&detail::upload_mesh_corner_attribute<MeshType>>(
1074 "upload_mesh_corner_attribute"_hs);
1075 entt::meta<MeshType>().template func<&detail::upload_mesh_facet_attribute<MeshType>>(
1076 "upload_mesh_facet_attribute"_hs);
1077 entt::meta<MeshType>().template func<&detail::upload_mesh_edge_attribute<MeshType>>(
1078 "upload_mesh_edge_attribute"_hs);
1079 entt::meta<MeshType>().template func<&detail::upload_submesh_indices<MeshType>>(
1080 "upload_submesh_indices"_hs);
1081
1082
1083 // Has attribute
1084 entt::meta<MeshType>().template func<&detail::has_mesh_vertex_attribute<MeshType>>(
1085 "has_mesh_vertex_attribute"_hs);
1086 entt::meta<MeshType>().template func<&detail::has_mesh_corner_attribute<MeshType>>(
1087 "has_mesh_corner_attribute"_hs);
1088 entt::meta<MeshType>().template func<&detail::has_mesh_facet_attribute<MeshType>>(
1089 "has_mesh_facet_attribute"_hs);
1090 entt::meta<MeshType>().template func<&detail::has_mesh_edge_attribute<MeshType>>(
1091 "has_mesh_edge_attribute"_hs);
1092 entt::meta<MeshType>().template func<&detail::has_mesh_indexed_attribute<MeshType>>(
1093 "has_mesh_indexed_attribute"_hs);
1094
1095
1096 // Picking
1097 entt::meta<MeshType>().template func<&detail::intersect_ray<MeshType>>("intersect_ray"_hs);
1098
1099 entt::meta<MeshType>().template func<&detail::select_vertices_in_frustum<MeshType>>(
1100 "select_vertices_in_frustum"_hs);
1101 entt::meta<MeshType>().template func<&detail::select_facets_in_frustum<MeshType>>(
1102 "select_facets_in_frustum"_hs);
1103 entt::meta<MeshType>().template func<&detail::select_edges_in_frustum<MeshType>>(
1104 "select_edges_in_frustum"_hs);
1105
1106
1107 entt::meta<MeshType>().template func<&detail::propagate_corner_selection<MeshType>>(
1108 "propagate_corner_selection"_hs);
1109 entt::meta<MeshType>().template func<&detail::propagate_vertex_selection<MeshType>>(
1110 "propagate_vertex_selection"_hs);
1111 entt::meta<MeshType>().template func<&detail::propagate_facet_selection<MeshType>>(
1112 "propagate_facet_selection"_hs);
1113 entt::meta<MeshType>().template func<&detail::combine_vertex_and_corner_selection<MeshType>>(
1114 "combine_vertex_and_corner_selection"_hs);
1115
1116
1117 entt::meta<MeshType>().template func<&detail::select_facets_by_color<MeshType>>(
1118 "select_facets_by_color"_hs);
1119 entt::meta<MeshType>().template func<&detail::select_edges_by_color<MeshType>>(
1120 "select_edges_by_color"_hs);
1121 entt::meta<MeshType>().template func<&detail::select_vertices_by_color<MeshType>>(
1122 "select_vertices_by_color"_hs);
1123
1124 entt::meta<MeshType>().template func<&detail::select_facets<MeshType>>("select_facets"_hs);
1125 entt::meta<MeshType>().template func<&detail::filter_closest_vertex<MeshType>>(
1126 "filter_closest_vertex"_hs);
1127}
1128
1129
1130} // namespace ui
1131} // namespace lagrange
Definition: Mesh.h:48
Index get_num_edges() const
Gets the number of edges.
Definition: Mesh.h:650
AttributeId compute_vertex_normal(SurfaceMesh< Scalar, Index > &mesh, VertexNormalOptions options={})
Compute per-vertex normals based on specified weighting type.
Definition: compute_vertex_normal.cpp:33
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
Lagrange UI Viewer and mini 3D engine.
Definition: AcceleratedPicking.h:22
LA_UI_API bool is_id_background(int id)
Is numerical ID from shader a background?
Definition: objectid_viewport.cpp:38
LA_UI_API int color_to_id(unsigned char r, unsigned char g, unsigned char b)
Translates shader output color to numerial ID.
Definition: objectid_viewport.cpp:32
LA_UI_API std::optional< std::pair< Entity, RayFacetHit > > intersect_ray(Registry &r, const Eigen::Vector3f &origin, const Eigen::Vector3f &dir, ui::Entity root=ui::NullEntity, Layer visible_layers=Layer(true), Layer hidden_layers=Layer(false))
Intersect ray with meshes in root's hierarchy Returns a pair of intersected entity and the correspond...
Definition: default_entities.cpp:502
Main namespace for Lagrange.
Definition: AABBIGL.h:30