10 #include <CloudViewerConfig.h>
16 #include <unordered_map>
17 #include <unordered_set>
52 #define GROUPS_USE_TREE 1
58 namespace visualization {
59 namespace visualizer {
62 static const std::string kShaderLit =
"defaultLit";
63 static const std::string kShaderUnlit =
"defaultUnlit";
64 static const std::string kShaderUnlitLines =
"unlitLine";
65 static const std::string kShaderGaussianSplat =
"gaussianSplat";
67 static const std::string kDefaultIBL =
"default";
74 MENU_ACTIONS_BASE = 1000
78 std::shared_ptr<T> GiveOwnership(T *ptr) {
79 return std::shared_ptr<T>(ptr);
82 class ButtonList :
public Widget {
84 explicit ButtonList(
int spacing) : spacing_(spacing) {}
89 const Constraints &constraints)
const override {
90 auto frames = CalcFrames(
context, constraints);
91 if (!frames.empty()) {
94 frames.back().GetBottom() - frames[0].y + spacing_);
96 return Size(width_, 0);
101 auto frames = CalcFrames(
context, Constraints());
102 auto &children = GetChildren();
103 for (
size_t i = 0; i < children.size(); ++i) {
104 children[i]->SetFrame(frames[i]);
108 size_t size()
const {
return GetChildren().size(); }
116 auto &f = GetFrame();
117 std::vector<Rect> frames;
121 for (
auto child : GetChildren()) {
122 auto pref = child->CalcPreferredSize(
context, constraints);
123 if (x > f.x && x + pref.width > f.x + width_) {
124 y = y + lineHeight + spacing_;
128 frames.emplace_back(x, y, pref.width, pref.height);
129 x += pref.width + spacing_;
130 lineHeight =
std::max(lineHeight, pref.height);
141 EmptyIfHiddenVert(
const char *text,
146 void SetVisible(
bool vis)
override {
147 Super::SetVisible(vis);
148 Super::SetIsOpen(vis);
153 const Constraints &constraints)
const override {
155 return Super::CalcPreferredSize(
context, constraints);
164 needsLayout_ =
false;
172 bool needsLayout_ =
false;
175 class DrawObjectTreeCell :
public Widget {
179 enum { FLAG_NONE = 0, FLAG_GROUP = (1 << 0), FLAG_TIME = (1 << 1) };
181 DrawObjectTreeCell(
const char *
name,
186 std::function<
void(
bool)> on_toggled) {
189 std::string time_str;
190 if (flags & FLAG_TIME) {
192 if (time ==
double(
int(time))) {
193 snprintf(buf,
sizeof(buf),
"t=%d",
int(time));
195 snprintf(buf,
sizeof(buf),
"t=%g", time);
197 time_str = std::string(buf);
203 checkbox_ = std::make_shared<Checkbox>(
" ");
204 checkbox_->SetChecked(is_checked);
205 checkbox_->SetOnChecked(on_toggled);
207 group_ = std::make_shared<Label>((flags & FLAG_GROUP) ? group :
"");
208 time_ = std::make_shared<Label>(time_str.c_str());
215 ~DrawObjectTreeCell() {}
217 std::shared_ptr<Checkbox> GetCheckbox() {
return checkbox_; }
218 std::shared_ptr<Label> GetName() {
return name_; }
221 const Constraints &constraints)
const override {
222 auto check_pref = checkbox_->CalcPreferredSize(
context, constraints);
223 auto name_pref =
name_->CalcPreferredSize(
context, constraints);
224 int w = check_pref.width + name_pref.width + GroupWidth(
context.theme) +
226 return Size(w,
std::max(check_pref.height, name_pref.height));
230 auto &
frame = GetFrame();
232 checkbox_->CalcPreferredSize(
context, Constraints()).width;
234 auto group_width = GroupWidth(
context.theme);
235 auto time_width = TimeWidth(
context.theme);
236 auto x = checkbox_->GetFrame().GetRight();
237 auto name_width =
frame.
GetRight() - group_width - time_width - x;
247 std::shared_ptr<Checkbox> checkbox_;
248 std::shared_ptr<Label>
name_;
249 std::shared_ptr<Label> group_;
250 std::shared_ptr<Label> time_;
253 if (flags_ & FLAG_GROUP) {
261 if (flags_ & FLAG_TIME) {
269 struct LightingProfile {
274 static const char *kCustomName =
"Custom";
275 static const std::vector<LightingProfile> gLightingProfiles = {
276 {
"Dark shadows", CloudViewerScene::LightingProfile::DARK_SHADOWS},
277 {
"Medium shadows", CloudViewerScene::LightingProfile::MED_SHADOWS},
278 {
"Soft shadows", CloudViewerScene::LightingProfile::SOFT_SHADOWS},
279 {
"No shadows", CloudViewerScene::LightingProfile::NO_SHADOWS}};
290 bool polygon_selection_unselects_ =
false;
291 bool selections_need_update_ =
true;
298 bool can_auto_show_settings_ =
true;
299 bool was_using_sun_follows_cam_ =
false;
301 double min_time_ = 0.0;
302 double max_time_ = 0.0;
303 double start_animation_clock_time_ = 0.0;
304 double next_animation_tick_clock_time_ = 0.0;
305 double last_animation_tick_clock_time_ = 0.0;
315 std::unordered_map<int, std::function<void(
O3DVisualizer &)>>
360 EmptyIfHiddenVert *groups_panel;
380 selections_ = std::make_shared<O3DVisualizerSelections>(*scene_);
384 [
this](
const std::map<
386 std::vector<std::pair<size_t, Eigen::Vector3d>>>
389 bool unselect_mode_requested =
391 if (unselect_mode_requested ||
392 polygon_selection_unselects_) {
393 selections_->UnselectIndices(indices);
395 selections_->SelectIndices(indices);
397 polygon_selection_unselects_ =
false;
402 o3dscene->SetBackground(ui_state_.
bg_color);
405 SetMouseMode(SceneWidget::Controls::ROTATE_CAMERA);
406 SetLightingProfile(gLightingProfiles[2]);
408 EnableSunFollowsCamera(
true);
413 auto half_em = int(std::round(0.5f *
float(em)));
414 auto v_spacing = int(std::round(0.25 *
float(em)));
416 settings.panel =
new Vert(half_em);
417 window_->
AddChild(GiveOwnership(settings.panel));
419 Margins margins(em, 0, half_em, 0);
420 Margins tabbed_margins(0, half_em, 0, 0);
422 settings.mouse_panel =
424 settings.panel->AddChild(GiveOwnership(settings.mouse_panel));
427 settings.mouse_panel->AddChild(GiveOwnership(settings.mouse_tab));
429 settings.view_panel =
new Vert(v_spacing, tabbed_margins);
430 settings.pick_panel =
new Vert(v_spacing, tabbed_margins);
431 settings.mouse_tab->AddTab(
"Scene", GiveOwnership(settings.view_panel));
432 settings.mouse_tab->AddTab(
"Selection",
433 GiveOwnership(settings.pick_panel));
434 settings.mouse_tab->SetOnSelectedTabChanged([
this](
int tab_idx) {
436 SetMouseMode(settings.view_mouse_mode);
443 auto MakeMouseButton = [
this](
const char *
name,
446 button->SetOnClicked([
this,
type]() { this->SetMouseMode(
type); });
447 this->settings.mouse_buttons[
type] = button;
450 auto *h =
new Horiz(v_spacing);
452 h->AddChild(GiveOwnership(MakeMouseButton(
453 "Arcball", SceneWidget::Controls::ROTATE_CAMERA)));
454 h->AddChild(GiveOwnership(
455 MakeMouseButton(
"Fly", SceneWidget::Controls::FLY)));
456 h->AddChild(GiveOwnership(
457 MakeMouseButton(
"Model", SceneWidget::Controls::ROTATE_MODEL)));
459 settings.view_panel->AddChild(GiveOwnership(h));
461 h =
new Horiz(v_spacing);
463 h->AddChild(GiveOwnership(MakeMouseButton(
464 "Sun Direction", SceneWidget::Controls::ROTATE_SUN)));
465 h->AddChild(GiveOwnership(MakeMouseButton(
466 "Environment", SceneWidget::Controls::ROTATE_IBL)));
468 settings.view_panel->AddChild(GiveOwnership(h));
469 settings.view_panel->AddFixed(half_em);
472 reset->SetOnClicked([
this]() { this->ResetCameraToDefault(); });
474 h =
new Horiz(v_spacing);
476 h->AddChild(GiveOwnership(reset));
478 settings.view_panel->AddChild(GiveOwnership(h));
481 settings.new_selection_set =
new SmallButton(
" + ");
482 settings.new_selection_set->SetOnClicked(
483 [
this]() { NewSelectionSet(); });
484 settings.delete_selection_set =
new SmallButton(
" - ");
485 settings.delete_selection_set->SetOnClicked([
this]() {
486 int idx = settings.selection_sets->GetSelectedIndex();
487 RemoveSelectionSet(idx);
489 settings.selection_sets =
new ListView();
490 settings.selection_sets->SetOnValueChanged([
this](
const char *,
bool) {
491 SelectSelectionSet(settings.selection_sets->GetSelectedIndex());
495 const char *selection_help = R
"(Cmd-click to select a point
496 Cmd-shift-click to deselect a point
497 Cmd-alt-click to polygon select)";
499 const char *selection_help = R
"(Ctrl-click to select a point
500 Ctrl-shift-click to deselect a point
501 Ctrl-alt-click to polygon select)";
505 h->AddChild(std::make_shared<Label>(selection_help));
507 settings.pick_panel->AddChild(GiveOwnership(h));
509 h =
new Horiz(
int(std::round(0.25f *
float(em))));
510 settings.polygon_selection_panel = h;
512 auto b = std::make_shared<SmallButton>(
"Select");
513 b->SetOnClicked([
this]() {
515 settings.polygon_selection_panel->SetVisible(
false);
518 b = std::make_shared<SmallButton>(
"Unselect");
519 b->SetOnClicked([
this]() {
520 polygon_selection_unselects_ =
true;
522 settings.polygon_selection_panel->SetVisible(
false);
525 b = std::make_shared<SmallButton>(
"Cancel");
526 b->SetOnClicked([
this]() {
528 settings.polygon_selection_panel->SetVisible(
false);
532 h->SetVisible(
false);
533 settings.pick_panel->AddChild(GiveOwnership(h));
535 h =
new Horiz(v_spacing);
536 h->AddChild(std::make_shared<Label>(
"Selection Sets"));
538 h->AddChild(GiveOwnership(settings.new_selection_set));
539 h->AddChild(GiveOwnership(settings.delete_selection_set));
540 settings.pick_panel->AddChild(GiveOwnership(h));
541 settings.pick_panel->AddChild(GiveOwnership(settings.selection_sets));
544 settings.scene_panel =
new CollapsableVert(
"Scene", v_spacing, margins);
545 settings.panel->AddChild(GiveOwnership(settings.scene_panel));
547 settings.show_skybox =
new Checkbox(
"Show Skybox");
548 settings.show_skybox->SetOnChecked(
549 [
this](
bool is_checked) { this->ShowSkybox(is_checked); });
551 settings.show_axes =
new Checkbox(
"Show Axis");
552 settings.show_axes->SetOnChecked(
553 [
this](
bool is_checked) { this->ShowAxes(is_checked); });
555 settings.show_ground =
new Checkbox(
"Show Ground");
556 settings.show_ground->SetOnChecked(
557 [
this](
bool is_checked) { this->ShowGround(is_checked); });
559 settings.ground_plane =
new Combobox();
560 settings.ground_plane->AddItem(
"XZ");
561 settings.ground_plane->AddItem(
"XY");
562 settings.ground_plane->AddItem(
"YZ");
563 settings.ground_plane->SetOnValueChanged([
this](
const char *item,
567 }
else if (idx == 2) {
575 h =
new Horiz(v_spacing);
576 h->AddChild(GiveOwnership(settings.show_axes));
578 h->AddChild(GiveOwnership(settings.show_skybox));
579 settings.scene_panel->AddChild(GiveOwnership(h));
580 settings.scene_panel->AddChild(GiveOwnership(settings.show_ground));
581 settings.scene_panel->AddChild(GiveOwnership(settings.ground_plane));
584 settings.bg_color->SetValue(ui_state_.
bg_color.x(),
587 settings.bg_color->SetOnValueChanged([
this](
const Color &c) {
593 settings.point_size->SetLimits(1, 10);
594 settings.point_size->SetValue(ui_state_.
point_size);
595 settings.point_size->SetOnValueChanged([
this](
const double newValue) {
596 this->SetPointSize(
int(newValue));
600 settings.shader->AddItem(
"Standard");
601 settings.shader->AddItem(
"Unlit");
602 settings.shader->AddItem(
"Normal Map");
603 settings.shader->AddItem(
"Depth");
604 settings.shader->SetOnValueChanged([
this](
const char *item,
int idx) {
606 this->SetShader(O3DVisualizer::Shader::UNLIT);
607 }
else if (idx == 2) {
608 this->SetShader(O3DVisualizer::Shader::NORMALS);
609 }
else if (idx == 3) {
610 this->SetShader(O3DVisualizer::Shader::DEPTH);
612 this->SetShader(O3DVisualizer::Shader::STANDARD);
617 for (
auto &
profile : gLightingProfiles) {
618 settings.lighting->AddItem(
profile.name.c_str());
620 settings.lighting->AddItem(kCustomName);
621 settings.lighting->SetOnValueChanged([
this](
const char *,
int index) {
622 if (index <
int(gLightingProfiles.size())) {
623 this->SetLightingProfile(gLightingProfiles[index]);
627 settings.basic_mode =
new Checkbox(
"");
628 settings.basic_mode->SetOnChecked(
629 [
this](
bool enable) { this->EnableBasicMode(enable); });
630 settings.wireframe_mode =
new Checkbox(
"");
631 settings.wireframe_mode->SetOnChecked(
632 [
this](
bool enable) { this->EnableWireframeMode(enable); });
634 auto *grid =
new VGrid(2, v_spacing);
635 settings.scene_panel->AddChild(GiveOwnership(grid));
637 grid->AddChild(std::make_shared<Label>(
"BG Color"));
638 grid->AddChild(GiveOwnership(settings.bg_color));
639 grid->AddChild(std::make_shared<Label>(
"PointSize"));
640 grid->AddChild(GiveOwnership(settings.point_size));
641 grid->AddChild(std::make_shared<Label>(
"Shader"));
642 grid->AddChild(GiveOwnership(settings.shader));
643 grid->AddChild(std::make_shared<Label>(
"Lighting"));
644 grid->AddChild(GiveOwnership(settings.lighting));
645 grid->AddChild(std::make_shared<Label>(
"Raw Mode"));
646 grid->AddChild(GiveOwnership(settings.basic_mode));
647 grid->AddChild(std::make_shared<Label>(
"Wireframe"));
648 grid->AddChild(GiveOwnership(settings.wireframe_mode));
652 settings.light_panel->SetIsOpen(
false);
653 settings.panel->AddChild(GiveOwnership(settings.light_panel));
655 h =
new Horiz(v_spacing);
656 settings.use_ibl =
new Checkbox(
"HDR map");
657 settings.use_ibl->SetChecked(ui_state_.
use_ibl);
658 settings.use_ibl->SetOnChecked([
this](
bool checked) {
659 this->ui_state_.
use_ibl = checked;
660 this->SetUIState(ui_state_);
661 this->settings.lighting->SetSelectedValue(kCustomName);
664 settings.use_sun =
new Checkbox(
"Sun");
665 settings.use_sun->SetChecked(settings.use_sun);
666 settings.use_sun->SetOnChecked([
this](
bool checked) {
667 this->ui_state_.
use_sun = checked;
668 this->SetUIState(ui_state_);
669 this->settings.lighting->SetSelectedValue(kCustomName);
672 h->AddChild(GiveOwnership(settings.use_ibl));
673 h->AddFixed(
int(std::round(
675 h->AddChild(GiveOwnership(settings.use_sun));
677 settings.light_panel->AddChild(
678 std::make_shared<Label>(
"Light sources"));
679 settings.light_panel->AddChild(GiveOwnership(h));
680 settings.light_panel->AddFixed(half_em);
682 grid =
new VGrid(2, v_spacing);
684 settings.ibl_names =
new Combobox();
685 for (
auto &
name : GetListOfIBLs()) {
686 settings.ibl_names->AddItem(
name.c_str());
688 settings.ibl_names->SetSelectedValue(kDefaultIBL.c_str());
689 settings.ibl_names->SetOnValueChanged([
this](
const char *val,
int idx) {
690 std::string resource_path =
692 this->SetIBL(resource_path + std::string(
"/") + std::string(val));
693 this->settings.lighting->SetSelectedValue(kCustomName);
695 grid->AddChild(std::make_shared<Label>(
"HDR map"));
696 grid->AddChild(GiveOwnership(settings.ibl_names));
699 settings.ibl_intensity->SetLimits(0.0, 150000.0);
701 settings.ibl_intensity->SetOnValueChanged([
this](
double new_value) {
703 this->SetUIState(ui_state_);
704 this->settings.lighting->SetSelectedValue(kCustomName);
706 grid->AddChild(std::make_shared<Label>(
"Intensity"));
707 grid->AddChild(GiveOwnership(settings.ibl_intensity));
709 settings.light_panel->AddChild(std::make_shared<Label>(
"Environment"));
710 settings.light_panel->AddChild(GiveOwnership(grid));
711 settings.light_panel->AddFixed(half_em);
713 grid =
new VGrid(2, v_spacing);
716 settings.sun_intensity->SetLimits(0.0, 250000.0);
718 settings.sun_intensity->SetOnValueChanged([
this](
double new_value) {
720 this->SetUIState(ui_state_);
721 this->settings.lighting->SetSelectedValue(kCustomName);
723 grid->AddChild(std::make_shared<Label>(
"Intensity"));
724 grid->AddChild(GiveOwnership(settings.sun_intensity));
727 settings.sun_dir->SetValue(ui_state_.
sun_dir);
728 settings.sun_dir->SetOnValueChanged([
this](
const Eigen::Vector3f &dir) {
730 this->SetUIState(ui_state_);
731 this->settings.lighting->SetSelectedValue(kCustomName);
734 [
this](
const Eigen::Vector3f &new_dir) {
735 this->ui_state_.
sun_dir = new_dir;
736 this->settings.sun_dir->SetValue(new_dir);
739 this->settings.lighting->SetSelectedValue(kCustomName);
741 grid->AddChild(std::make_shared<Label>(
"Direction"));
742 grid->AddChild(GiveOwnership(settings.sun_dir));
745 settings.sun_follows_camera->SetChecked(
true);
746 settings.sun_follows_camera->SetOnChecked([
this](
bool checked) {
748 this->SetUIState(ui_state_);
749 EnableSunFollowsCamera(checked);
751 grid->AddChild(GiveOwnership(settings.sun_follows_camera));
752 grid->AddChild(std::make_shared<gui::Label>(
"Sun Follows Camera"));
755 settings.sun_color->SetValue(ui_state_.
sun_color);
756 settings.sun_color->SetOnValueChanged([
this](
const Color &new_color) {
760 this->SetUIState(ui_state_);
761 this->settings.lighting->SetSelectedValue(kCustomName);
763 grid->AddChild(std::make_shared<Label>(
"Color"));
764 grid->AddChild(GiveOwnership(settings.sun_color));
766 settings.light_panel->AddChild(
767 std::make_shared<Label>(
"Sun (Directional light)"));
768 settings.light_panel->AddChild(GiveOwnership(grid));
771 settings.geometries_panel =
773 settings.panel->AddChild(GiveOwnership(settings.geometries_panel));
775 settings.geometries =
new TreeView();
776 settings.geometries_panel->AddChild(GiveOwnership(settings.geometries));
780 settings.groups_panel =
781 new EmptyIfHiddenVert(
"Groups", v_spacing, margins);
782 settings.panel->AddChild(GiveOwnership(settings.groups_panel));
785 settings.groups_panel->AddChild(GiveOwnership(settings.groups));
787 settings.groups_panel->SetVisible(
false);
791 settings.time_panel =
new EmptyIfHiddenVert(
"Time", v_spacing, margins);
792 settings.panel->AddChild(GiveOwnership(settings.time_panel));
795 settings.time_slider->SetOnValueChanged([
this](
double new_value) {
797 this->UpdateTimeUI();
798 this->SetCurrentTime(new_value);
802 settings.time_edit->SetOnValueChanged([
this](
double new_value) {
804 this->UpdateTimeUI();
805 this->SetCurrentTime(new_value);
809 settings.play->SetOnClicked(
810 [
this]() { this->SetAnimating(settings.play->GetIsOn()); });
812 h =
new Horiz(v_spacing);
813 h->AddChild(GiveOwnership(settings.time_slider));
814 h->AddChild(GiveOwnership(settings.time_edit));
815 h->AddChild(GiveOwnership(settings.play));
816 settings.time_panel->AddChild(GiveOwnership(h));
818 settings.time_panel->SetVisible(
false);
822 settings.actions_panel =
823 new EmptyIfHiddenVert(
"Custom Actions", v_spacing, margins);
824 settings.panel->AddChild(GiveOwnership(settings.actions_panel));
825 settings.actions_panel->SetVisible(
false);
827 settings.actions =
new ButtonList(v_spacing);
828 settings.actions_panel->AddChild(GiveOwnership(settings.actions));
832 settings.polygon_selection_panel->SetVisible(
true);
837 std::shared_ptr<geometry::Geometry> geom,
838 std::shared_ptr<t::geometry::Geometry> tgeom,
839 std::shared_ptr<rendering::TriangleMeshModel> model,
841 const std::string &group,
844 std::string group_name = group;
845 if (group_name ==
"") {
846 group_name =
"default";
848 bool is_default_color =
false;
849 bool no_shadows =
false;
854 is_default_color =
false;
856 std::dynamic_pointer_cast<t::geometry::PointCloud>(tgeom);
865 bool is_gaussian_splat =
false;
867 auto cloud = std::dynamic_pointer_cast<geometry::PointCloud>(geom);
868 auto lines = std::dynamic_pointer_cast<geometry::LineSet>(geom);
869 auto obb = std::dynamic_pointer_cast<geometry::OrientedBoundingBox>(
872 std::dynamic_pointer_cast<geometry::AxisAlignedBoundingBox>(
874 auto mesh = std::dynamic_pointer_cast<ccMesh>(geom);
876 std::dynamic_pointer_cast<geometry::VoxelGrid>(geom);
877 auto octree = std::dynamic_pointer_cast<geometry::Octree>(geom);
880 std::dynamic_pointer_cast<t::geometry::PointCloud>(tgeom);
882 std::dynamic_pointer_cast<t::geometry::TriangleMesh>(tgeom);
884 std::dynamic_pointer_cast<t::geometry::LineSet>(tgeom);
889 }
else if (t_cloud) {
890 if (t_cloud->IsGaussianSplat()) is_gaussian_splat =
true;
896 }
else if (t_lines) {
900 has_colors = (obb->color_ != Eigen::Vector3d{0.0, 0.0, 0.0});
904 (aabb->GetColor() != Eigen::Vector3d{0.0, 0.0, 0.0});
907 has_normals = mesh->hasNormals() || mesh->HasTriangleNormals();
911 t_mesh->HasTriangleNormals();
913 }
else if (voxel_grid) {
922 mat.
shader = kShaderUnlit;
923 if (lines || obb || aabb || t_lines) {
924 mat.
shader = kShaderUnlitLines;
927 is_default_color =
true;
930 is_default_color =
false;
935 is_default_color =
false;
937 if (is_gaussian_splat) {
938 mat.
shader = kShaderGaussianSplat;
939 mat.
sh_degree = t_cloud->GaussianSplatGetSHOrder();
944 if (t_mesh && t_mesh->HasMaterial()) {
945 t_mesh->GetMaterial().ToMaterialRecord(mat);
946 }
else if (t_cloud && t_cloud->HasMaterial()) {
947 t_cloud->GetMaterial().ToMaterialRecord(mat);
948 }
else if (t_lines && t_lines->HasMaterial()) {
949 t_lines->GetMaterial().ToMaterialRecord(mat);
953 if (mesh && mesh->materials_.size() > 0) {
954 std::size_t material_index;
955 if (mesh->hasTriangleMaterialIds()) {
956 auto minmax_it = std::minmax_element(
957 mesh->triangle_material_ids_.begin(),
958 mesh->triangle_material_ids_.end());
959 if (*minmax_it.first != *minmax_it.second) {
961 "Only a single material is "
962 "supported for TriangleMesh visualization, "
963 "only the first referenced material will be "
964 "used. Use TriangleMeshModel if more than one "
965 "material is required.");
967 material_index = *minmax_it.first;
971 auto &mesh_material = mesh->materials_[material_index].second;
972 mat.
base_color = {mesh_material.baseColor.r(),
973 mesh_material.baseColor.g(),
974 mesh_material.baseColor.b(),
975 mesh_material.baseColor.a()};
981 mesh_material.baseClearCoatRoughness;
985 mat.
ao_img = mesh_material.ambientOcclusion;
1001 AddGroup(group_name);
1002 bool update_for_time = (min_time_ == max_time_ && time != max_time_);
1003 min_time_ =
std::min(min_time_, time);
1004 max_time_ =
std::max(max_time_, time);
1006 UpdateTimeUIRange();
1007 settings.time_panel->SetVisible(
true);
1009 if (update_for_time) {
1014 if (can_auto_show_settings_ &&
1015 (added_groups_.size() == 2 || update_for_time)) {
1019 objects_.push_back({
name, geom, tgeom, model, mat, group_name, time,
1020 is_visible, is_default_color});
1021 AddObjectToTree(objects_.back());
1026 scene->AddGeometry(
name, geom.get(), mat);
1028 scene->AddGeometry(
name, tgeom.get(), mat);
1030 scene->AddModel(
name, *model);
1033 "No valid geometry specified to O3DVisualizer. Only "
1034 "supported geometries are Geometry3D and TGeometry "
1035 "PointClouds and TriangleMeshes.");
1039 scene->GetScene()->GeometryShadows(
name,
false,
false);
1041 UpdateGeometryVisibility(objects_.back());
1051 std::shared_ptr<t::geometry::Geometry> tgeom,
1052 uint32_t update_flags) {
1054 std::dynamic_pointer_cast<t::geometry::PointCloud>(tgeom);
1057 "Only TGeometry PointClouds can currently be updated using "
1058 "UpdateGeometry. Try removing the geometry that needs to "
1059 "be updated then adding the update geometry.");
1062 scene_->
GetScene()->GetScene()->UpdateGeometry(
name, *t_cloud,
1069 for (
size_t i = 0; i < objects_.size(); ++i) {
1071 group = objects_[i].group;
1072 settings.object2itemid.erase(objects_[i].
name);
1073 objects_.erase(objects_.begin() + i);
1080 std::set<std::string> groups;
1081 min_time_ = max_time_ = 0.0;
1082 for (
size_t i = 0; i < objects_.size(); ++i) {
1083 auto &o = objects_[i];
1084 min_time_ =
std::min(min_time_, o.time);
1085 max_time_ =
std::max(max_time_, o.time);
1086 groups.insert(o.group);
1088 if (min_time_ == max_time_) {
1089 SetAnimating(
false);
1091 UpdateTimeUIRange();
1093 added_groups_ = groups;
1094 std::set<std::string> enabled;
1096 if (groups.find(g) != groups.end()) {
1112 for (
auto &o : objects_) {
1113 if (o.name ==
name) {
1114 if (show != o.is_visible) {
1115 o.is_visible = show;
1117 auto id = settings.object2itemid[o.name];
1118 auto cell = settings.geometries->GetItem(
id);
1120 std::dynamic_pointer_cast<DrawObjectTreeCell>(cell);
1122 obj_cell->GetCheckbox()->SetChecked(show);
1125 UpdateGeometryVisibility(o);
1128 if (selections_->IsActive()) {
1129 UpdateSelectableGeometry();
1131 selections_need_update_ =
true;
1140 for (
auto &o : objects_) {
1141 if (o.name ==
name) {
1149 for (
auto &o : objects_) {
1150 if (o.name ==
name) {
1159 for (
auto &o : objects_) {
1160 if (o.name ==
name) {
1161 o.material = *material;
1162 scene_->
GetScene()->ModifyGeometryMaterial(
name, *material);
1170 if (inspect_mat.
shader ==
"defaultLit" ||
1171 inspect_mat.
shader ==
"defaultLitTransparency" ||
1172 inspect_mat.
shader ==
"defaultListSSR") {
1173 inspect_mat.
shader =
"defaultLit";
1175 inspect_mat.
base_color = {1.f, 1.f, 1.f, 1.f};
1188 inspect_mat.
ao_img.reset();
1198 std::shared_ptr<ccMesh> mesh) {
1199 auto new_mesh = mesh->cloneMesh();
1200 if (!new_mesh->HasTriangleNormals()) {
1201 new_mesh->ComputeTriangleNormals();
1203 return std::shared_ptr<ccMesh>(new_mesh);
1209 for (
auto &o : objects_) {
1210 scene_->
GetScene()->ShowGeometry(o.name,
false);
1211 inspection_objects_.push_back(o);
1212 inspection_objects_.back().name = o.name +
"_inspect";
1215 for (
auto &o : inspection_objects_) {
1217 CreateInspectionModeMaterial(
1222 std::dynamic_pointer_cast<ccMesh>(o.geometry)) {
1223 o.geometry = DuplicateGeometryForInspection(mesh);
1225 scene_->
GetScene()->AddGeometry(o.name, o.geometry.get(),
1227 }
else if (o.tgeometry) {
1228 CreateInspectionModeMaterial(
1230 o.tgeometry->GetGeometryType() ==
1233 scene_->
GetScene()->AddGeometry(o.name, o.tgeometry.get(),
1235 }
else if (o.model) {
1236 for (
auto &mat : o.model->materials_) {
1237 CreateInspectionModeMaterial(mat,
false);
1239 for (
auto &mi : o.model->meshes_) {
1240 auto new_mesh = DuplicateGeometryForInspection(mi.mesh);
1243 scene_->
GetScene()->AddModel(o.name, *o.model);
1248 for (
auto &o : inspection_objects_) {
1249 scene_->
GetScene()->RemoveGeometry(o.name);
1251 inspection_objects_.clear();
1253 for (
auto &o : objects_) {
1254 scene_->
GetScene()->ShowGeometry(o.name,
true);
1263 mat.
shader =
"unlitLine";
1268 for (
auto &o : objects_) {
1271 scene_->
GetScene()->ShowGeometry(o.name,
false);
1272 auto mesh = std::dynamic_pointer_cast<ccMesh>(o.geometry);
1276 draw_obj.
name = o.name +
"_wireframe";
1279 wireframe_objects_.push_back(draw_obj);
1283 }
else if (o.tgeometry &&
1284 o.tgeometry->GetGeometryType() ==
1288 scene_->
GetScene()->ShowGeometry(o.name,
false);
1289 auto tmesh = std::dynamic_pointer_cast<
1291 auto tmesh_legacy = tmesh->
ToLegacy();
1295 draw_obj.
name = o.name +
"_wireframe";
1298 wireframe_objects_.push_back(draw_obj);
1302 }
else if (o.model) {
1304 scene_->
GetScene()->ShowGeometry(o.name,
false);
1305 for (
auto &mi : o.model->meshes_) {
1309 draw_obj.
name = mi.mesh_name +
"_wireframe";
1312 wireframe_objects_.push_back(draw_obj);
1321 for (
auto &o : wireframe_objects_) {
1322 scene_->
GetScene()->RemoveGeometry(o.name);
1324 wireframe_objects_.clear();
1326 for (
auto &o : objects_) {
1327 scene_->
GetScene()->ShowGeometry(o.name,
true);
1339 const Eigen::Vector3f ¢er,
1340 const Eigen::Vector3f &eye,
1341 const Eigen::Vector3f &up) {
1342 scene_->
LookAt(center, eye, up);
1347 const Eigen::Matrix4d &extrinsic) {
1349 scene_->
GetScene()->GetBoundingBox());
1354 const Eigen::Matrix4d &extrinsic,
1355 int intrinsic_width_px,
1356 int intrinsic_height_px) {
1357 scene_->
SetupCamera(intrinsic, extrinsic, intrinsic_width_px,
1358 intrinsic_height_px,
1359 scene_->
GetScene()->GetBoundingBox());
1365 scene_->
SetupCamera(60.0f, scene->GetBoundingBox(), {0.0f, 0.0f, 0.0f});
1370 std::shared_ptr<geometry::Image> bg_image) {
1371 auto old_default_color = CalcDefaultUnlitColor();
1373 settings.bg_color->SetValue(bg_color.x(), bg_color.y(), bg_color.z());
1375 scene->SetBackground(ui_state_.
bg_color, bg_image);
1377 auto new_default_color = CalcDefaultUnlitColor();
1378 if (new_default_color != old_default_color) {
1379 for (
auto &o : objects_) {
1380 if (o.is_color_default) {
1381 o.material.base_color = new_default_color;
1382 OverrideMaterial(o.name, o.material,
1392 if (cancel_auto_show) {
1393 can_auto_show_settings_ =
false;
1396 settings.panel->SetVisible(show);
1399 menubar->SetChecked(MENU_SETTINGS, show);
1406 settings.show_skybox->SetChecked(show);
1407 scene_->
GetScene()->ShowSkybox(show);
1413 settings.show_axes->SetChecked(show);
1414 scene_->
GetScene()->ShowAxes(show);
1420 settings.show_ground->SetChecked(show);
1428 settings.ground_plane->SetSelectedIndex(0);
1430 settings.ground_plane->SetSelectedIndex(1);
1432 settings.ground_plane->SetSelectedIndex(2);
1442 auto low_scene = scene_->
GetScene()->GetScene();
1445 auto low_scene = scene_->
GetScene()->GetScene();
1448 low_scene->SetSunLightDirection(
1449 scene_->
GetScene()->GetCamera()->GetForwardVector());
1454 low_scene->SetSunLightDirection(ui_state_.
sun_dir);
1460 settings.show_skybox->SetEnabled(enable);
1461 settings.lighting->SetEnabled(enable);
1462 settings.use_ibl->SetEnabled(enable);
1463 settings.ibl_intensity->SetEnabled(enable);
1464 settings.ibl_names->SetEnabled(enable);
1465 settings.use_sun->SetEnabled(enable);
1466 settings.sun_dir->SetEnabled(enable);
1467 settings.sun_color->SetEnabled(enable);
1468 settings.mouse_buttons[SceneWidget::Controls::ROTATE_SUN]->SetEnabled(
1470 settings.sun_follows_camera->SetEnabled(enable);
1471 settings.wireframe_mode->SetEnabled(enable);
1475 auto o3dscene = scene_->
GetScene();
1476 auto view = o3dscene->GetView();
1477 auto low_scene = o3dscene->GetScene();
1480 o3dscene->SetBackground({1.f, 1.f, 1.f, 1.f});
1481 low_scene->ShowSkybox(
false);
1482 low_scene->EnableIndirectLight(
false);
1483 low_scene->EnableSunLight(
true);
1484 low_scene->SetSunLightIntensity(160000.f);
1485 view->SetShadowing(
false, View::ShadowType::kPCF);
1486 view->SetPostProcessing(
false);
1488 EnableSunFollowsCamera(
true);
1489 settings.sun_follows_camera->SetChecked(
true);
1490 was_using_sun_follows_cam_ =
false;
1492 was_using_sun_follows_cam_ =
true;
1495 settings.wireframe_mode->SetChecked(
false);
1496 EnableWireframeMode(
false);
1497 UpdateGeometryForInspectionMode(
true);
1498 EnableInspectionRelatedUI(
false);
1502 view->SetPostProcessing(
true);
1503 view->SetShadowing(
true, View::ShadowType::kPCF);
1504 UpdateGeometryForInspectionMode(
false);
1505 EnableInspectionRelatedUI(
true);
1506 if (!was_using_sun_follows_cam_) {
1507 settings.sun_follows_camera->SetChecked(
false);
1508 EnableSunFollowsCamera(
false);
1510 SetUIState(ui_state_);
1515 auto o3dscene = scene_->
GetScene();
1516 auto view = o3dscene->GetView();
1517 auto low_scene = o3dscene->GetScene();
1518 UpdateGeometryForWireframeMode(enable);
1520 o3dscene->SetBackground({0.1f, 0.1f, 0.1f, 1.0f});
1521 low_scene->ShowSkybox(
false);
1522 view->SetWireframe(
true);
1525 view->SetWireframe(
false);
1526 SetUIState(ui_state_);
1532 settings.point_size->SetValue(
double(px));
1534 px = int(ConvertToScaledPixels(px));
1535 for (
auto &o : objects_) {
1537 if (o.model)
continue;
1539 o.material.point_size = float(px);
1540 OverrideMaterial(o.name, o.material, ui_state_.
scene_shader);
1542 for (
auto &o : inspection_objects_) {
1543 o.material.point_size = float(px);
1544 OverrideMaterial(o.name, o.material, ui_state_.
scene_shader);
1547 auto bbox_extend = scene_->
GetScene()->GetBoundingBox().GetExtent();
1548 auto psize = double(
std::max(5, px)) * 0.000666 *
1550 std::max(bbox_extend.y(), bbox_extend.z()));
1551 selections_->SetPointSize(psize);
1560 px = int(ConvertToScaledPixels(px));
1561 for (
auto &o : objects_) {
1563 if (o.model)
continue;
1565 o.material.line_width = float(px);
1566 OverrideMaterial(o.name, o.material, ui_state_.
scene_shader);
1568 for (
auto &o : inspection_objects_) {
1569 o.material.line_width = float(px);
1570 OverrideMaterial(o.name, o.material, ui_state_.
scene_shader);
1580 for (
auto &o : objects_) {
1581 OverrideMaterial(o.name, o.material, shader);
1583 for (
auto &o : inspection_objects_) {
1584 OverrideMaterial(o.name, o.material, shader);
1592 bool is_lines = (original_material.
shader ==
"unlitLine");
1593 bool is_gradient = (original_material.
shader ==
"unlitGradient");
1597 if (shader == Shader::STANDARD || is_gradient ||
1598 (shader == Shader::UNLIT && is_lines)) {
1599 scene->ModifyGeometryMaterial(
name, original_material);
1602 m.
shader = GetShaderString(shader);
1603 scene->ModifyGeometryMaterial(
name, m);
1608 return std::round(px * window_->
GetScaling());
1613 case Shader::STANDARD:
1616 return "defaultUnlit";
1617 case Shader::NORMALS:
1623 "O3DVisualizer::GetShaderString(): unhandled Shader "
1630 std::string ibl_path;
1635 std::string(
"/") + std::string(kDefaultIBL);
1641 if (
path.find(
"_ibl.ktx") ==
path.size() - 8) {
1642 ibl_path =
path.substr(0,
path.size() - 8);
1645 "Could not load IBL path. Filename must be of the form "
1646 "'name_ibl.ktx' and be paired with 'name_skybox.ktx'");
1659 scene_->
GetScene()->GetScene()->SetIndirectLight(ibl_path);
1665 SetUIState(ui_state_);
1669 Eigen::Vector3f sun_dir = {0.577f, -0.577f, -0.577f};
1671 scene->SetLighting(
profile.profile, sun_dir);
1673 CloudViewerScene::LightingProfile::HARD_SHADOWS);
1675 CloudViewerScene::LightingProfile::NO_SHADOWS);
1677 int(scene->GetScene()->GetIndirectLightIntensity());
1679 int(scene->GetScene()->GetSunLightIntensity());
1681 ui_state_.
sun_color = {1.0f, 1.0f, 1.0f};
1682 SetUIState(ui_state_);
1684 this->settings.lighting->SetSelectedValue(
profile.name.c_str());
1688 if (selections_->IsActive()) {
1689 selections_->MakeInactive();
1694 settings.view_mouse_mode = mode;
1695 for (
const auto &t_b : settings.mouse_buttons) {
1696 t_b.second->SetOn(
false);
1698 auto it = settings.mouse_buttons.find(mode);
1699 if (it != settings.mouse_buttons.end()) {
1700 it->second->SetOn(
true);
1705 if (
name == settings.mouse_panel->GetText()) {
1706 settings.mouse_panel->SetIsOpen(open);
1707 }
else if (
name == settings.scene_panel->GetText()) {
1708 settings.scene_panel->SetIsOpen(open);
1709 }
else if (
name == settings.light_panel->GetText()) {
1710 settings.light_panel->SetIsOpen(open);
1711 }
else if (
name == settings.geometries_panel->GetText()) {
1712 settings.geometries_panel->SetIsOpen(open);
1717 if (selections_->GetNumberOfSets() == 0) {
1720 if (selections_need_update_) {
1721 UpdateSelectableGeometry();
1723 selections_->MakeActive();
1728 return selections_->GetSets();
1736 for (
auto &o : objects_) {
1737 UpdateGeometryVisibility(o);
1741 if (on_animation_) {
1755 start_animation_clock_time_ = now;
1756 last_animation_tick_clock_time_ = now;
1757 if (on_animation_tick_) {
1761 [
this]() ->
bool {
return this->OnAnimationTick(); });
1765 SetCurrentTime(0.0);
1766 next_animation_tick_clock_time_ = 0.0;
1768 settings.time_slider->SetEnabled(!is_animating);
1769 settings.time_edit->SetEnabled(!is_animating);
1776 on_animation_tick_ = [
this, &o3dvis, cb]() ->
bool {
1778 auto dt = now - this->last_animation_tick_clock_time_;
1779 auto total_time = now - this->start_animation_clock_time_;
1780 this->last_animation_tick_clock_time_ = now;
1782 auto result = cb(o3dvis, dt, total_time);
1784 if (
result == TickResult::REDRAW) {
1792 on_animation_tick_ =
nullptr;
1803 bool is_new_lighting =
1810 bool in_basic_mode = settings.basic_mode->IsChecked();
1812 if (&new_state != &ui_state_) {
1813 ui_state_ = new_state;
1816 if (ibl_path_changed) {
1822 SetBackground(ui_state_.
bg_color,
nullptr);
1823 if (!in_basic_mode) ShowSkybox(ui_state_.
show_skybox);
1827 if (point_size_changed) {
1830 if (line_width_changed) {
1834 settings.use_ibl->SetChecked(ui_state_.
use_ibl);
1835 settings.use_sun->SetChecked(ui_state_.
use_sun);
1838 settings.sun_dir->SetValue(ui_state_.
sun_dir);
1839 settings.sun_color->SetValue(ui_state_.
sun_color);
1841 ui_state_.
ibl_intensity = settings.ibl_intensity->GetIntValue();
1842 ui_state_.
sun_intensity = settings.sun_intensity->GetIntValue();
1845 settings.sun_dir->SetEnabled(
false);
1846 settings.mouse_buttons[SceneWidget::Controls::ROTATE_SUN]
1847 ->SetEnabled(
false);
1849 settings.sun_dir->SetEnabled(
true);
1850 settings.mouse_buttons[SceneWidget::Controls::ROTATE_SUN]
1854 if (is_new_lighting) {
1855 settings.lighting->SetSelectedValue(kCustomName);
1858 auto *raw_scene = scene_->
GetScene()->GetScene();
1859 if (!in_basic_mode) {
1860 raw_scene->EnableIndirectLight(ui_state_.
use_ibl);
1861 raw_scene->SetIndirectLightIntensity(
1863 raw_scene->SetSunLightColor(ui_state_.
sun_color);
1865 raw_scene->SetSunLightDirection(ui_state_.
sun_dir);
1868 raw_scene->EnableSunLight(ui_state_.
use_sun);
1872 for (
auto &group : added_groups_) {
1875 EnableGroup(group, enabled);
1879 if (old_is_animating != new_is_animating) {
1881 SetAnimating(new_is_animating);
1889 if (added_groups_.find(group) == added_groups_.end()) {
1890 added_groups_.insert(group);
1893 if (added_groups_.size() == 2) {
1897 if (added_groups_.find(group) == added_groups_.end()) {
1898 added_groups_.insert(group);
1901 auto cell = std::make_shared<CheckableTextTreeCell>(
1902 group.c_str(),
true, [
this, group](
bool is_on) {
1903 this->EnableGroup(group, is_on);
1905 auto root = settings.groups->GetRootItem();
1906 settings.groups->AddItem(root, cell);
1908 if (added_groups_.size() >= 2) {
1909 settings.groups_panel->SetVisible(
true);
1916 auto group_it = settings.group2itemid.find(group);
1917 if (group_it != settings.group2itemid.end()) {
1918 auto cell = settings.geometries->GetItem(group_it->second);
1920 std::dynamic_pointer_cast<CheckableTextTreeCell>(cell);
1922 group_cell->GetCheckbox()->SetChecked(enable);
1931 for (
auto &o : objects_) {
1932 UpdateGeometryVisibility(o);
1939 if (added_groups_.size() >= 2) {
1940 auto it = settings.group2itemid.find(o.
group);
1941 if (it != settings.group2itemid.end()) {
1942 parent = it->second;
1944 auto cell = std::make_shared<CheckableTextTreeCell>(
1945 o.
group.c_str(),
true,
1946 [
this, group = o.
group](
bool is_on) {
1947 this->EnableGroup(group, is_on);
1949 parent = settings.geometries->AddItem(parent, cell);
1950 settings.group2itemid[o.
group] = parent;
1955 int flag = DrawObjectTreeCell::FLAG_NONE;
1956 #if !GROUPS_USE_TREE
1957 flag |= (added_groups_.size() >= 2 ? DrawObjectTreeCell::FLAG_GROUP
1960 flag |= (min_time_ != max_time_ ? DrawObjectTreeCell::FLAG_TIME : 0);
1961 auto cell = std::make_shared<DrawObjectTreeCell>(
1963 [
this,
name = o.
name](
bool is_on) {
1964 ShowGeometry(name, is_on);
1966 auto id = settings.geometries->AddItem(parent, cell);
1967 settings.object2itemid[o.
name] = id;
1972 settings.group2itemid.clear();
1974 settings.object2itemid.clear();
1975 settings.geometries->Clear();
1977 for (
auto &o : objects_) {
1983 bool enabled = (min_time_ < max_time_);
1984 settings.time_slider->SetEnabled(enabled);
1985 settings.time_edit->SetEnabled(enabled);
1986 settings.play->SetEnabled(enabled);
1988 settings.time_slider->SetLimits(min_time_, max_time_);
1995 settings.time_slider->SetValue(ui_state_.
current_time);
2000 scene_->
GetScene()->ShowGeometry(o.
name, IsGeometryVisible(o));
2011 return (is_visible & is_current & is_group_enabled);
2015 selections_->NewSet();
2016 UpdateSelectionSetList();
2017 SelectSelectionSet(
int(selections_->GetNumberOfSets()) - 1);
2021 selections_->RemoveSet(index);
2022 if (selections_->GetNumberOfSets() == 0) {
2026 selections_->NewSet();
2028 UpdateSelectionSetList();
2032 settings.selection_sets->SetSelectedIndex(index);
2033 selections_->SelectSet(index);
2038 size_t n = selections_->GetNumberOfSets();
2039 int idx = settings.selection_sets->GetSelectedIndex();
2043 std::vector<std::string> items;
2045 for (
size_t i = 0; i < n; ++i) {
2046 std::stringstream s;
2047 s <<
"Set " << (i + 1);
2048 items.push_back(s.str());
2050 settings.selection_sets->SetItems(items);
2051 SelectSelectionSet(idx);
2056 std::vector<SceneWidget::PickableGeometry> pickable;
2058 size_t model_mesh_count = 0;
2059 size_t model_count = 0;
2060 for (
auto &o : objects_) {
2061 if (!IsGeometryVisible(o)) {
2064 if (o.model.get()) {
2066 model_mesh_count += o.model.get()->meshes_.size();
2069 pickable.reserve(objects_.size() + model_mesh_count - model_count);
2070 for (
auto &o : objects_) {
2071 if (!IsGeometryVisible(o)) {
2074 if (o.model.get()) {
2075 for (
auto &g : o.model->meshes_) {
2076 pickable.emplace_back(g.mesh_name, g.mesh.get(),
2080 pickable.emplace_back(o.name, o.geometry.get(),
2084 selections_->SetSelectableGeometry(pickable);
2089 if (now >= next_animation_tick_clock_time_) {
2091 UpdateAnimationTickClockTime(now);
2098 next_animation_tick_clock_time_ = now + ui_state_.
frame_delay;
2103 scene_->
GetScene()->GetScene()->RenderToImage(
2104 [
this,
path](std::shared_ptr<geometry::Image>
image)
mutable {
2108 (std::string(
"Could not write image to ") +
2118 auto dlg = std::make_shared<gui::Dialog>(
"About");
2120 auto title = std::make_shared<gui::Label>(
2121 (std::string(
"CloudViewer ") + CLOUDVIEWER_VERSION).c_str());
2122 auto text = std::make_shared<gui::Label>(
2123 "The MIT License (MIT)\n"
2124 "Copyright (c) 2018-2023 www.cloudViewer.org\n\n"
2126 "Permission is hereby granted, free of charge, to any person "
2127 "obtaining a copy of this software and associated "
2128 "documentation files (the \"Software\"), to deal in the "
2129 "Software without restriction, including without limitation "
2130 "the rights to use, copy, modify, merge, publish, distribute, "
2131 "sublicense, and/or sell copies of the Software, and to "
2132 "permit persons to whom the Software is furnished to do so, "
2133 "subject to the following conditions:\n\n"
2135 "The above copyright notice and this permission notice shall "
2136 "be included in all copies or substantial portions of the "
2139 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY "
2140 "KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE "
2141 "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR "
2142 "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR "
2143 "COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "
2144 "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR "
2145 "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE "
2146 "SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.");
2147 auto ok = std::make_shared<gui::Button>(
"OK");
2148 ok->SetOnClicked([
this]() { this->window_->
CloseDialog(); });
2151 auto layout = std::make_shared<gui::Vert>(0, margins);
2154 auto v = std::make_shared<gui::ScrollableVert>(0);
2156 layout->AddChild(v);
2159 dlg->AddChild(layout);
2165 auto dlg = std::make_shared<gui::FileDialog>(
2167 dlg->AddFilter(
".png",
"PNG images (.png)");
2168 dlg->AddFilter(
"",
"All files");
2169 dlg->SetOnCancel([
this]() { this->window_->
CloseDialog(); });
2170 dlg->SetOnDone([
this](
const char *
path) {
2172 this->ExportCurrentImage(
path);
2182 if (added_names_.find(
name) == added_names_.end()) {
2190 std::stringstream s;
2191 s <<
name <<
"_" << n;
2193 }
while (added_names_.find(unique) != added_names_.end());
2199 float luminosity = 0.21f * ui_state_.
bg_color.x() +
2202 if (luminosity >= 0.5f) {
2203 return {0.0f, 0.0f, 0.0f, 1.0f};
2205 return {1.0f, 1.0f, 1.0f, 1.0f};
2210 std::vector<std::string> ibls;
2211 std::vector<std::string> resource_files;
2212 std::string resource_path =
2216 std::sort(resource_files.begin(), resource_files.end());
2217 for (
auto &f : resource_files) {
2218 if (f.find(
"_ibl.ktx") == f.size() - 8) {
2221 ibls.push_back(
name);
2231 impl_->Construct(
this);
2234 auto on_geometry = [
this](std::shared_ptr<geometry::Geometry> geom,
2235 const std::string &
path,
int time,
2236 const std::string &layer) {
2237 impl_->AddGeometry(
path, geom,
nullptr,
nullptr,
nullptr, layer, time,
2239 if (impl_->objects_.size() == 1) {
2240 impl_->ResetCameraToDefault();
2243 impl_->message_processor_ =
2244 std::make_shared<MessageProcessor>(
this, on_geometry);
2250 auto menu = std::make_shared<Menu>();
2251 #if defined(__APPLE__)
2254 auto app_menu = std::make_shared<Menu>();
2255 app_menu->AddItem(
"About", MENU_ABOUT);
2256 menu->AddMenu(
"CloudViewer", app_menu);
2260 auto file_menu = std::make_shared<Menu>();
2261 file_menu->AddItem(
"Export Current Image...", MENU_EXPORT_RGB);
2262 file_menu->AddSeparator();
2264 menu->AddMenu(
"File", file_menu);
2267 auto actions_menu = std::make_shared<Menu>();
2268 actions_menu->AddItem(
"Show Settings", MENU_SETTINGS);
2269 actions_menu->SetChecked(MENU_SETTINGS,
false);
2270 menu->AddMenu(
"Actions", actions_menu);
2271 impl_->settings.actions_menu = actions_menu.get();
2273 #if !defined(__APPLE__)
2274 auto help_menu = std::make_shared<Menu>();
2275 help_menu->AddItem(
"About", MENU_ABOUT);
2276 menu->AddMenu(
"Help", help_menu);
2283 [
this]() { this->impl_->OnExportRGB(); });
2286 [
this]() { this->impl_->OnToggleSettings(); });
2288 impl_->ShowSettings(
false,
false);
2294 return impl_->scene_->GetScene().get();
2298 impl_->receiver_ = std::make_shared<io::rpc::ZMQReceiver>(address, timeout);
2299 impl_->receiver_->SetMessageProcessor(impl_->message_processor_);
2303 impl_->receiver_->Start();
2304 }
catch (std::exception &e) {
2310 if (impl_->receiver_) {
2313 impl_->receiver_.reset();
2321 impl_->settings.actions->AddChild(GiveOwnership(button));
2324 impl_->settings.actions_panel->SetVisible(
true);
2325 impl_->settings.actions_panel->SetIsOpen(
true);
2327 if (impl_->can_auto_show_settings_ &&
2328 impl_->settings.actions->size() == 1) {
2329 impl_->ShowSettings(
true);
2333 if (impl_->settings.menuid2action.empty()) {
2334 impl_->settings.actions_menu->AddSeparator();
2336 int id = MENU_ACTIONS_BASE + int(impl_->settings.menuid2action.size());
2337 impl_->settings.actions_menu->AddItem(
name.c_str(),
id);
2338 impl_->settings.menuid2action[id] =
callback;
2343 const Eigen::Vector4f &bg_color,
2344 std::shared_ptr<geometry::Image> bg_image ) {
2345 impl_->SetBackground(bg_color, bg_image);
2351 const std::string &
name,
2352 std::shared_ptr<ccHObject> geom,
2354 const std::string &group ,
2357 impl_->AddGeometry(
name, geom,
nullptr,
nullptr, material, group, time,
2362 const std::string &
name,
2363 std::shared_ptr<t::geometry::Geometry> tgeom,
2365 const std::string &group ,
2368 impl_->AddGeometry(
name,
nullptr, tgeom,
nullptr, material, group, time,
2373 const std::string &
name,
2374 std::shared_ptr<rendering::TriangleMeshModel> model,
2376 const std::string &group ,
2379 impl_->AddGeometry(
name,
nullptr,
nullptr, model, material, group, time,
2384 impl_->Add3DLabel(pos, text);
2390 std::shared_ptr<t::geometry::Geometry> tgeom,
2391 uint32_t update_flags) {
2392 impl_->UpdateGeometry(
name, tgeom, update_flags);
2396 return impl_->RemoveGeometry(
name);
2400 return impl_->ShowGeometry(
name, show);
2404 const std::string &
name)
const {
2405 return impl_->GetGeometry(
name);
2409 const std::string &
name)
const {
2410 return impl_->GetGeometryMaterial(
name);
2415 impl_->ModifyGeometryMaterial(
name, material);
2425 impl_->SetIBLIntensity(intensity);
2433 impl_->SetGroundPlane(plane);
2437 impl_->EnableBasicMode(enable);
2441 impl_->EnableWireframeMode(enable);
2445 impl_->SetPointSize(point_size);
2449 impl_->SetLineWidth(line_width);
2453 impl_->SetMouseMode(mode);
2457 impl_->SetPanelOpen(
name, open);
2461 impl_->EnableGroup(group, enable);
2464 std::vector<O3DVisualizerSelections::SelectionSet>
2466 return impl_->GetSelectionSets();
2470 return impl_->ui_state_.frame_delay;
2474 impl_->ui_state_.frame_delay = secs;
2478 return impl_->ui_state_.time_step;
2482 impl_->ui_state_.time_step = time_step;
2492 impl_->UpdateTimeUIRange();
2493 impl_->settings.time_panel->SetVisible(impl_->min_time_ < impl_->max_time_);
2497 return impl_->ui_state_.current_time;
2503 return impl_->ui_state_.is_animating;
2507 impl_->SetAnimating(is_animating);
2511 const Eigen::Vector3f ¢er,
2512 const Eigen::Vector3f &eye,
2513 const Eigen::Vector3f &up) {
2514 impl_->SetupCamera(fov, center, eye, up);
2518 const Eigen::Matrix4d &extrinsic) {
2519 impl_->SetupCamera(intrinsic, extrinsic);
2523 const Eigen::Matrix4d &extrinsic,
2524 int intrinsic_width_px,
2525 int intrinsic_height_px) {
2526 impl_->SetupCamera(intrinsic, extrinsic, intrinsic_width_px,
2527 intrinsic_height_px);
2531 return impl_->ResetCameraToDefault();
2535 return impl_->ui_state_;
2541 impl_->on_animation_ = [
this, cb](
double t) { cb(*
this, t); };
2543 impl_->on_animation_ =
nullptr;
2549 impl_->SetOnAnimationTick(*
this, cb);
2553 impl_->ExportCurrentImage(
path);
2557 auto em =
context.theme.font_size;
2558 int settings_width = 16 *
context.theme.font_size;
2559 #if !GROUPS_USE_TREE
2560 if (impl_->added_groups_.size() >= 2) {
2561 settings_width += 5 *
context.theme.font_size;
2564 if (impl_->min_time_ != impl_->max_time_) {
2565 settings_width += 3 *
context.theme.font_size;
2569 impl_->settings.actions->SetWidth(settings_width -
2570 int(std::round(1.5 * em)));
2571 if (impl_->settings.panel->IsVisible()) {
2572 impl_->scene_->SetFrame(
2573 Rect(f.x, f.y, f.width - settings_width, f.height));
2574 impl_->settings.panel->SetFrame(
Rect(f.GetRight() - settings_width, f.y,
2575 settings_width, f.height));
2577 impl_->scene_->SetFrame(f);
std::shared_ptr< core::Tensor > image
std::function< void(std::shared_ptr< core::Tensor >)> callback
CloudViewerScene::LightingProfile profile
Contains the pinhole camera intrinsic parameters.
static std::shared_ptr< LineSet > CreateFromTriangleMesh(const ccMesh &mesh)
GeometryType
Specifies possible geometry types.
A triangle mesh contains vertices and triangles.
ccMesh ToLegacy() const
Convert to a legacy CloudViewer TriangleMesh.
static Application & GetInstance()
std::shared_ptr< Menu > GetMenubar() const
const char * GetResourcePath() const
Lays out widgets horizontally.
static std::shared_ptr< Horiz > MakeCentered(std::shared_ptr< Widget > w)
Lays out widgets vertically.
void SetNeedsLayout()
Instructs the window to relayout before the next draw.
const Theme & GetTheme() const
void AddChild(std::shared_ptr< Widget > w)
void SetOnMenuItemActivated(Menu::ItemId item_id, std::function< void()> callback)
Rect GetContentRect() const
visualization::rendering::Renderer & GetRenderer() const
virtual void Layout(const LayoutContext &context)
void ShowDialog(std::shared_ptr< Dialog > dlg)
void SetOnTickEvent(std::function< bool()> callback)
void CloseDialog()
Closes the dialog.
void ShowMessageBox(const char *title, const char *message)
float GetScaling() const
Returns the scaling factor from OS pixels to device pixels.
virtual Eigen::Vector3f GetForwardVector() const =0
void SetPointSize(int point_size)
void SetAnimationDuration(double sec)
double GetAnimationDuration() const
void StartRPCInterface(const std::string &address, int timeout)
Starts the RPC interface. See io/rpc/ZMQReceiver for the parameters.
void SetMouseMode(gui::SceneWidget::Controls mode)
void SetOnAnimationTick(std::function< TickResult(O3DVisualizer &, double, double)> cb)
void EnableWireframeMode(bool enable)
void ShowSettings(bool show)
void SetGroundPlane(rendering::Scene::GroundPlane plane)
void ExportCurrentImage(const std::string &path)
void SetBackground(const Eigen::Vector4f &bg_color, std::shared_ptr< geometry::Image > bg_image=nullptr)
DrawObject GetGeometry(const std::string &name) const
Returns Visualizer's internal DrawObject for the named geometry.
void SetOnAnimationFrame(std::function< void(O3DVisualizer &, double)> cb)
double GetAnimationTimeStep() const
rendering::MaterialRecord GetGeometryMaterial(const std::string &name) const
void EnableGroup(const std::string &group, bool enable)
void SetPanelOpen(const std::string &name, bool open)
void ShowGeometry(const std::string &name, bool show)
Show/hide the named geometry.
void SetupCamera(float fov, const Eigen::Vector3f ¢er, const Eigen::Vector3f &eye, const Eigen::Vector3f &up)
bool GetIsAnimating() const
void SetAnimating(bool is_animating)
void SetAnimationFrameDelay(double secs)
rendering::CloudViewerScene * GetScene() const
void RemoveGeometry(const std::string &name)
Removes the named geometry from the Visualizer.
void ShowGround(bool show)
void SetLineWidth(int line_width)
void SetIBL(const std::string &path)
void UpdateGeometry(const std::string &name, std::shared_ptr< t::geometry::Geometry > tgeom, uint32_t update_flags)
double GetCurrentTime() const
std::vector< O3DVisualizerSelections::SelectionSet > GetSelectionSets() const
void SetIBLIntensity(float intensity)
void ShowSkybox(bool show)
void EnableBasicMode(bool enable)
void Add3DLabel(const Eigen::Vector3f &pos, const char *text)
void Layout(const gui::LayoutContext &context)
double GetAnimationFrameDelay() const
void AddAction(const std::string &name, std::function< void(O3DVisualizer &)> callback)
void SetShader(Shader shader)
UIState GetUIState() const
void SetCurrentTime(double t)
void ResetCameraToDefault()
void ModifyGeometryMaterial(const std::string &name, const rendering::MaterialRecord *material)
void SetAnimationTimeStep(double time_step)
O3DVisualizer(const std::string &title, int width, int height)
void AddGeometry(const std::string &name, std::shared_ptr< ccHObject > geom, const rendering::MaterialRecord *material=nullptr, const std::string &group="", double time=0.0, bool is_visible=true)
ccGuiPythonInstance * GetInstance() noexcept
bool WriteImage(const std::string &filename, const geometry::Image &image, int quality=kCloudViewerImageIODefaultQuality)
static const std::string path
bool ListFilesInDirectory(const std::string &directory, std::vector< std::string > &filenames)
bool FileExists(const std::string &filename)
std::string GetFileNameWithoutDirectory(const std::string &filename)
void Draw(const std::vector< std::shared_ptr< ccHObject >> &geometries, const std::string &window_name, int width, int height, const std::vector< DrawAction > &actions)
Generic file read and write utility for python interface.
std::shared_ptr< geometry::Image > normal_img
std::shared_ptr< geometry::Image > clearcoat_roughness_img
std::shared_ptr< geometry::Image > clearcoat_img
std::shared_ptr< geometry::Image > albedo_img
std::shared_ptr< geometry::Image > ao_img
float base_clearcoat_roughness
std::shared_ptr< geometry::Image > metallic_img
Eigen::Vector4f emissive_color
std::shared_ptr< geometry::Image > roughness_img
std::shared_ptr< geometry::Image > anisotropy_img
std::shared_ptr< geometry::Image > reflectance_img
Eigen::Vector4f base_color
rendering::MaterialRecord material
std::shared_ptr< ccHObject > geometry
void SetOnAnimationTick(O3DVisualizer &o3dvis, std::function< TickResult(O3DVisualizer &, double, double)> cb)
Button * delete_selection_set
std::function< void(double)> on_animation_
void AddGroup(const std::string &group)
void AddGeometry(const std::string &name, std::shared_ptr< geometry::Geometry > geom, std::shared_ptr< t::geometry::Geometry > tgeom, std::shared_ptr< rendering::TriangleMeshModel > model, const rendering::MaterialRecord *material, const std::string &group, double time, bool is_visible)
std::shared_ptr< O3DVisualizerSelections > selections_
void RemoveSelectionSet(int index)
Checkbox * sun_follows_camera
void UpdateAnimationTickClockTime(double now)
CollapsableVert * mouse_panel
void SetPointSize(int px)
std::vector< O3DVisualizerSelections::SelectionSet > GetSelectionSets() const
void UpdateGeometryVisibility(const DrawObject &o)
void UpdateGeometryForInspectionMode(bool enable)
void ShowSettings(bool show, bool cancel_auto_show=true)
void EnableSunFollowsCamera(bool enable)
void ResetCameraToDefault()
void SetAnimating(bool is_animating)
Horiz * polygon_selection_panel
void SetUIState(const UIState &new_state)
std::map< std::string, TreeView::ItemId > group2itemid
CollapsableVert * geometries_panel
void SetupCamera(const Eigen::Matrix3d &intrinsic, const Eigen::Matrix4d &extrinsic, int intrinsic_width_px, int intrinsic_height_px)
void SetupCamera(const camera::PinholeCameraIntrinsic &intrinsic, const Eigen::Matrix4d &extrinsic)
void Add3DLabel(const Eigen::Vector3f &pos, const char *text)
std::set< std::string > added_groups_
EmptyIfHiddenVert * time_panel
void ShowSkybox(bool show)
void OverrideMaterial(const std::string &name, const MaterialRecord &original_material, O3DVisualizer::Shader shader)
void SetShader(O3DVisualizer::Shader shader)
std::shared_ptr< ccMesh > DuplicateGeometryForInspection(std::shared_ptr< ccMesh > mesh)
std::vector< std::string > GetListOfIBLs()
Eigen::Vector4f CalcDefaultUnlitColor()
void SetBackground(const Eigen::Vector4f &bg_color, std::shared_ptr< geometry::Image > bg_image)
std::shared_ptr< MessageProcessor > message_processor_
void SetPanelOpen(const std::string &name, bool open)
void UpdateSelectableGeometry()
bool IsGeometryVisible(const DrawObject &o)
void UpdateGeometry(const std::string &name, std::shared_ptr< t::geometry::Geometry > tgeom, uint32_t update_flags)
CollapsableVert * light_panel
EmptyIfHiddenVert * actions_panel
std::map< std::string, TreeView::ItemId > object2itemid
void RemoveGeometry(const std::string &name)
void ModifyGeometryMaterial(const std::string &name, const MaterialRecord *material)
std::shared_ptr< io::rpc::ZMQReceiver > receiver_
void Construct(O3DVisualizer *w)
void ShowGeometry(const std::string &name, bool show)
std::vector< DrawObject > objects_
void EnableInspectionRelatedUI(bool enable)
SceneWidget::Controls view_mouse_mode
void ExportCurrentImage(const std::string &path)
O3DVisualizer::DrawObject GetGeometry(const std::string &name) const
void SetupCamera(float fov, const Eigen::Vector3f ¢er, const Eigen::Vector3f &eye, const Eigen::Vector3f &up)
Checkbox * wireframe_mode
void SetLightingProfile(const LightingProfile &profile)
std::string UniquifyName(const std::string &name)
std::unordered_map< int, std::function< void(O3DVisualizer &)> > menuid2action
std::map< SceneWidget::Controls, Button * > mouse_buttons
const char * GetShaderString(O3DVisualizer::Shader shader)
void ShowGround(bool show)
ListView * selection_sets
void SetLineWidth(int px)
void EnableGroup(const std::string &group, bool enable)
void SetIBL(std::string path)
std::set< std::string > added_names_
void SelectSelectionSet(int index)
void UpdateSelectionSetList()
void UpdateGeometryForWireframeMode(bool enable)
void AddObjectToTree(const DrawObject &o)
Button * new_selection_set
void EnableBasicMode(bool enable)
void SetIBLIntensity(float intensity)
MaterialRecord GetGeometryMaterial(const std::string &name)
CollapsableVert * scene_panel
void EnableWireframeMode(bool enable)
void SetGroundPlane(rendering::Scene::GroundPlane plane)
void SetCurrentTime(double t)
std::vector< DrawObject > wireframe_objects_
std::vector< DrawObject > inspection_objects_
void CreateInspectionModeMaterial(MaterialRecord &inspect_mat, bool pcd=false)
void SetMouseMode(SceneWidget::Controls mode)
std::function< bool()> on_animation_tick_
float ConvertToScaledPixels(int px)
gui::SceneWidget::Controls mouse_mode
rendering::Scene::GroundPlane ground_plane
std::set< std::string > enabled_groups
Eigen::Vector3f sun_color