def __init__(self): self.mouse_model = gui.SceneWidget.Controls.ROTATE_CAMERA self.bg_color = gui.Color(1, 1, 1) self.show_skybox = False self.show_axes = False self.use_ibl = True self.use_sun = True self.new_ibl_name = None # clear to None after loading self.ibl_intensity = 45000 self.sun_intensity = 45000 self.sun_dir = [0.577, -0.577, -0.577] self.sun_color = gui.Color(1, 1, 1) self.apply_material = True # clear to False after processing self._materials = { Settings.LIT: rendering.Material(), Settings.UNLIT: rendering.Material(), Settings.NORMALS: rendering.Material(), Settings.DEPTH: rendering.Material() } self._materials[Settings.LIT].base_color = [0.9, 0.9, 0.9, 1.0] self._materials[Settings.LIT].shader = Settings.LIT self._materials[Settings.UNLIT].base_color = [0.9, 0.9, 0.9, 1.0] self._materials[Settings.UNLIT].shader = Settings.UNLIT self._materials[Settings.NORMALS].shader = Settings.NORMALS self._materials[Settings.DEPTH].shader = Settings.DEPTH # Conveniently, assigning from self._materials[...] assigns a reference, # not a copy, so if we change the property of a material, then switch # to another one, then come back, the old setting will still be there. self.material = self._materials[Settings.LIT]
def _visualize(self, title, width, height): gui.Application.instance.initialize() self._init_user_interface(title, width, height) # override just to set background color to back :) bgcolor = gui.ColorEdit() bgcolor.color_value = gui.Color(0, 0, 0) self._on_bgcolor_changed(bgcolor.color_value) self._3d.scene.downsample_threshold = 400000 # Turn all the objects off except the first one for name, node in self._name2treenode.items(): node.checkbox.checked = False self._3d.scene.show_geometry(name, False) for name in [self._objects.data_names[0]]: self._name2treenode[name].checkbox.checked = True self._3d.scene.show_geometry(name, True) def on_done_ui(): # Add bounding boxes here: bounding boxes belonging to the dataset # will not be loaded until now. self._update_bounding_boxes() self._update_datasource_combobox() self._update_shaders_combobox() # Display "colors" by default if available, "points" if not available_attrs = self._get_available_attrs() self._set_shader(self.SOLID_NAME, force_update=True) if "colors" in available_attrs: self._datasource_combobox.selected_text = "colors" elif "points" in available_attrs: self._datasource_combobox.selected_text = "points" self._dont_update_geometry = True self._on_datasource_changed( self._datasource_combobox.selected_text, self._datasource_combobox.selected_index ) self._update_geometry_colors() self._dont_update_geometry = False # _datasource_combobox was empty, now isn't, re-layout. self.window.set_needs_layout() self._update_geometry() self.setup_camera() self._load_geometries(self._objects.data_names, on_done_ui) gui.Application.instance.run()
def _apply_settings(self): bg_color = [ self.settings.bg_color.red, self.settings.bg_color.green, self.settings.bg_color.blue, self.settings.bg_color.alpha ] self._scene.scene.set_background(bg_color) self._scene.scene.show_skybox(self.settings.show_skybox) self._scene.scene.show_axes(self.settings.show_axes) if self.settings.new_ibl_name is not None: self._scene.scene.scene.set_indirect_light( self.settings.new_ibl_name) # Clear new_ibl_name, so we don't keep reloading this image every # time the settings are applied. self.settings.new_ibl_name = None self._scene.scene.scene.enable_indirect_light(self.settings.use_ibl) self._scene.scene.scene.set_indirect_light_intensity( self.settings.ibl_intensity) sun_color = [ self.settings.sun_color.red, self.settings.sun_color.green, self.settings.sun_color.blue ] self._scene.scene.scene.set_sun_light(self.settings.sun_dir, sun_color, self.settings.sun_intensity) self._scene.scene.scene.enable_sun_light(self.settings.use_sun) if self.settings.apply_material: self._scene.scene.update_material(self.settings.material) self.settings.apply_material = False self._bg_color.color_value = self.settings.bg_color self._show_skybox.checked = self.settings.show_skybox self._show_axes.checked = self.settings.show_axes self._use_ibl.checked = self.settings.use_ibl self._use_sun.checked = self.settings.use_sun self._ibl_intensity.int_value = self.settings.ibl_intensity self._sun_intensity.int_value = self.settings.sun_intensity self._sun_dir.vector_value = self.settings.sun_dir self._sun_color.color_value = self.settings.sun_color self._material_prefab.enabled = ( self.settings.material.shader == Settings.LIT) c = gui.Color(self.settings.material.base_color[0], self.settings.material.base_color[1], self.settings.material.base_color[2], self.settings.material.base_color[3]) self._material_color.color_value = c self._point_size.double_value = self.settings.material.point_size
def low_level(): app = gui.Application.instance app.initialize() points = make_point_cloud(100, (0, 0, 0), 1.0) w = app.create_window("Open3D - 3D Text", 1024, 768) widget3d = gui.SceneWidget() widget3d.scene = rendering.Open3DScene(w.renderer) mat = rendering.MaterialRecord() mat.shader = "defaultUnlit" mat.point_size = 5 * w.scaling widget3d.scene.add_geometry("Points", points, mat) for idx in range(0, len(points.points)): l = widget3d.add_3d_label(points.points[idx], "{}".format(idx)) l.color = gui.Color(points.colors[idx][0], points.colors[idx][1], points.colors[idx][2]) l.scale = np.random.uniform(0.5, 3.0) bbox = widget3d.scene.bounding_box widget3d.setup_camera(60.0, bbox, bbox.get_center()) w.add_child(widget3d) app.run()
def __init__(self): self.window = gui.Window("Test") # self.window = gui.Window("Test", 640, 480) # self.window = gui.Window("Test", 640, 480, x=50, y=100) w = self.window # for more concise code # Rather than specifying sizes in pixels, which may vary in size based # on the monitor, especially on macOS which has 220 dpi monitors, use # the em-size. This way sizings will be proportional to the font size, # which will create a more visually consistent size across platforms. em = w.theme.font_size # Widgets are laid out in layouts: gui.Horiz, gui.Vert, # gui.CollapsableVert, and gui.VGrid. By nesting the layouts we can # achieve complex designs. Usually we use a vertical layout as the # topmost widget, since widgets tend to be organized from top to bottom. # Within that, we usually have a series of horizontal layouts for each # row. layout = gui.Vert(0, gui.Margins(0.5 * em, 0.5 * em, 0.5 * em, 0.5 * em)) # Create the menu. The menu is global (because the macOS menu is global), # so only create it once. if gui.Application.instance.menubar is None: menubar = gui.Menu() test_menu = gui.Menu() test_menu.add_item("An option", ExampleWindow.MENU_CHECKABLE) test_menu.set_checked(ExampleWindow.MENU_CHECKABLE, True) test_menu.add_item("Unavailable feature", ExampleWindow.MENU_DISABLED) test_menu.set_enabled(ExampleWindow.MENU_DISABLED, False) test_menu.add_separator() test_menu.add_item("Quit", ExampleWindow.MENU_QUIT) # On macOS the first menu item is the application menu item and will # always be the name of the application (probably "Python"), # regardless of what you pass in here. The application menu is # typically where About..., Preferences..., and Quit go. menubar.add_menu("Test", test_menu) gui.Application.instance.menubar = menubar # Each window needs to know what to do with the menu items, so we need # to tell the window how to handle menu items. w.set_on_menu_item_activated(ExampleWindow.MENU_CHECKABLE, self._on_menu_checkable) w.set_on_menu_item_activated(ExampleWindow.MENU_QUIT, self._on_menu_quit) # Create a file-chooser widget. One part will be a text edit widget for # the filename and clicking on the button will let the user choose using # the file dialog. self._fileedit = gui.TextEdit() filedlgbutton = gui.Button("...") filedlgbutton.horizontal_padding_em = 0.5 filedlgbutton.vertical_padding_em = 0 filedlgbutton.set_on_clicked(self._on_filedlg_button) # (Create the horizontal widget for the row. This will make sure the # text editor takes up as much space as it can.) fileedit_layout = gui.Horiz() fileedit_layout.add_child(gui.Label("Model file")) fileedit_layout.add_child(self._fileedit) fileedit_layout.add_fixed(0.25 * em) fileedit_layout.add_child(filedlgbutton) # add to the top-level (vertical) layout layout.add_child(fileedit_layout) # Create a collapsable vertical widget, which takes up enough vertical # space for all its children when open, but only enough for text when # closed. This is useful for property pages, so the user can hide sets # of properties they rarely use. All layouts take a spacing parameter, # which is the spacinging between items in the widget, and a margins # parameter, which specifies the spacing of the left, top, right, # bottom margins. (This acts like the 'padding' property in CSS.) collapse = gui.CollapsableVert("Widgets", 0.33 * em, gui.Margins(em, 0, 0, 0)) self._label = gui.Label("Lorem ipsum dolor") self._label.text_color = gui.Color(1.0, 0.5, 0.0) collapse.add_child(self._label) # Create a checkbox. Checking or unchecking would usually be used to set # a binary property, but in this case it will show a simple message box, # which illustrates how to create simple dialogs. cb = gui.Checkbox("Enable some really cool effect") cb.set_on_checked(self._on_cb) # set the callback function collapse.add_child(cb) # Create a color editor. We will change the color of the orange label # above when the color changes. color = gui.ColorEdit() color.color_value = self._label.text_color color.set_on_value_changed(self._on_color) collapse.add_child(color) # This is a combobox, nothing fancy here, just set a simple function to # handle the user selecting an item. combo = gui.Combobox() combo.add_item("Show point labels") combo.add_item("Show point velocity") combo.add_item("Show bounding boxes") combo.set_on_selection_changed(self._on_combo) collapse.add_child(combo) # Add a simple image logo = gui.ImageLabel(basedir + "/icon-32.png") collapse.add_child(logo) # Add a list of items lv = gui.ListView() lv.set_items(["Ground", "Trees", "Buildings" "Cars", "People"]) lv.selected_index = lv.selected_index + 2 # initially is -1, so now 1 lv.set_on_selection_changed(self._on_list) collapse.add_child(lv) # Add a tree view tree = gui.TreeView() tree.add_item(tree.get_root_item(), "Camera") geo_id = tree.add_item(tree.get_root_item(), "Geometries") mesh_id = tree.add_item(geo_id, "Mesh") tree.add_item(mesh_id, "Triangles") tree.add_item(mesh_id, "Albedo texture") tree.add_item(mesh_id, "Normal map") points_id = tree.add_item(geo_id, "Points") tree.can_select_items_with_children = True tree.set_on_selection_changed(self._on_tree) # does not call on_selection_changed: user did not change selection tree.selected_item = points_id collapse.add_child(tree) # Add two number editors, one for integers and one for floating point # Number editor can clamp numbers to a range, although this is more # useful for integers than for floating point. intedit = gui.NumberEdit(gui.NumberEdit.INT) intedit.int_value = 0 intedit.set_limits(1, 19) # value coerced to 1 intedit.int_value = intedit.int_value + 2 # value should be 3 doubleedit = gui.NumberEdit(gui.NumberEdit.DOUBLE) numlayout = gui.Horiz() numlayout.add_child(gui.Label("int")) numlayout.add_child(intedit) numlayout.add_fixed( em) # manual spacing (could set it in Horiz() ctor) numlayout.add_child(gui.Label("double")) numlayout.add_child(doubleedit) collapse.add_child(numlayout) # Create a progress bar. It ranges from 0.0 to 1.0. self._progress = gui.ProgressBar() self._progress.value = 0.25 # 25% complete self._progress.value = self._progress.value + 0.08 # 0.25 + 0.08 = 33% prog_layout = gui.Horiz(em) prog_layout.add_child(gui.Label("Progress...")) prog_layout.add_child(self._progress) collapse.add_child(prog_layout) # Create a slider. It acts very similar to NumberEdit except that the # user moves a slider and cannot type the number. slider = gui.Slider(gui.Slider.INT) slider.set_limits(5, 13) slider.set_on_value_changed(self._on_slider) collapse.add_child(slider) # Create a text editor. The placeholder text (if not empty) will be # displayed when there is no text, as concise help, or visible tooltip. tedit = gui.TextEdit() tedit.placeholder_text = "Edit me some text here" # on_text_changed fires whenever the user changes the text (but not if # the text_value property is assigned to). tedit.set_on_text_changed(self._on_text_changed) # on_value_changed fires whenever the user signals that they are finished # editing the text, either by pressing return or by clicking outside of # the text editor, thus losing text focus. tedit.set_on_value_changed(self._on_value_changed) collapse.add_child(tedit) # Create a widget for showing/editing a 3D vector vedit = gui.VectorEdit() vedit.vector_value = [1, 2, 3] vedit.set_on_value_changed(self._on_vedit) collapse.add_child(vedit) # Create a VGrid layout. This layout specifies the number of columns # (two, in this case), and will place the first child in the first # column, the second in the second, the third in the first, the fourth # in the second, etc. # So: # 2 cols 3 cols 4 cols # | 1 | 2 | | 1 | 2 | 3 | | 1 | 2 | 3 | 4 | # | 3 | 4 | | 4 | 5 | 6 | | 5 | 6 | 7 | 8 | # | 5 | 6 | | 7 | 8 | 9 | | 9 | 10 | 11 | 12 | # | ... | | ... | | ... | vgrid = gui.VGrid(2) vgrid.add_child(gui.Label("Trees")) vgrid.add_child(gui.Label("12 items")) vgrid.add_child(gui.Label("People")) vgrid.add_child(gui.Label("2 (93% certainty)")) vgrid.add_child(gui.Label("Cars")) vgrid.add_child(gui.Label("5 (87% certainty)")) collapse.add_child(vgrid) collapse.add_child(vgrid) # Create a tab control. This is really a set of N layouts on top of each # other, but with only one selected. tabs = gui.TabControl() tab1 = gui.Vert() tab1.add_child(gui.Checkbox("Enable option 1")) tab1.add_child(gui.Checkbox("Enable option 2")) tab1.add_child(gui.Checkbox("Enable option 3")) tabs.add_tab("Options", tab1) tab2 = gui.Vert() tab2.add_child(gui.Label("No plugins detected")) tab2.add_stretch() tabs.add_tab("Plugins", tab2) collapse.add_child(tabs) # Quit button. (Typically this is a menu item) button_layout = gui.Horiz() ok_button = gui.Button("Ok") ok_button.set_on_clicked(self._on_ok) button_layout.add_stretch() button_layout.add_child(ok_button) layout.add_child(collapse) layout.add_child(button_layout) # We're done, set the window's layout w.add_child(layout)
def __init__(self, width, height): self.window = gui.Window("Open3D", width, height) w = self.window # to make the code more concise # 3D widget self._scene = gui.SceneWidget(w) # ---- Settings panel ---- # Rather than specifying sizes in pixels, which may vary in size based # on the monitor, especially on macOS which has 220 dpi monitors, use # the em-size. This way sizings will be proportional to the font size, # which will create a more visually consistent size across platforms. em = w.theme.font_size separation_height = int(round(0.5 * em)) # Widgets are laid out in layouts: gui.Horiz, gui.Vert, # gui.CollapsableVert, and gui.VGrid. By nesting the layouts we can # achieve complex designs. Usually we use a vertical layout as the # topmost widget, since widgets tend to be organized from top to bottom. # Within that, we usually have a series of horizontal layouts for each # row. All layouts take a spacing parameter, which is the spacing # between items in the widget, and a margins parameter, which specifies # the spacing of the left, top, right, bottom margins. (This acts like # the 'padding' property in CSS.) self._settings_panel = gui.Vert( 0, gui.Margins(0.25 * em, 0.25 * em, 0.25 * em, 0.25 * em)) # Create a collapsable vertical widget, which takes up enough vertical # space for all its children when open, but only enough for text when # closed. This is useful for property pages, so the user can hide sets # of properties they rarely use. view_ctrls = gui.CollapsableVert("View controls", 0.25 * em, gui.Margins(em, 0, 0, 0)) self._arcball_button = gui.Button("Arcball") self._fly_button = gui.Button("Fly") self._model_button = gui.Button("Model") self._sun_button = gui.Button("Sun") self._ibl_button = gui.Button("Environment") view_ctrls.add_child(gui.Label("Mouse controls")) # We want two rows of buttons, so make two horizontal layouts. We also # want the buttons centered, which we can do be putting a stretch item # as the first and last item. Stretch items take up as much space as # possible, and since there are two, they will each take half the extra # space, thus centering the buttons. h = gui.Horiz(0.25 * em) # row 1 h.add_stretch() h.add_child(self._arcball_button) h.add_child(self._fly_button) h.add_child(self._model_button) h.add_stretch() view_ctrls.add_child(h) h = gui.Horiz(0.25 * em) # row 2 h.add_stretch() h.add_child(self._sun_button) h.add_child(self._ibl_button) h.add_stretch() view_ctrls.add_child(h) self._show_skymap = gui.Checkbox("Show skymap") view_ctrls.add_fixed(separation_height) view_ctrls.add_child(self._show_skymap) bg_color = gui.ColorEdit() bg_color.color_value = gui.Color(1, 1, 1, 1) self._on_bg_color(bg_color.color_value) bg_color.set_on_value_changed(self._on_bg_color) grid = gui.VGrid(2, 0.25 * em) grid.add_child(gui.Label("BG Color")) grid.add_child(bg_color) view_ctrls.add_child(grid) self._show_axes = gui.Checkbox("Show axes") view_ctrls.add_fixed(separation_height) view_ctrls.add_child(self._show_axes) profiles = gui.Combobox() profiles.add_item("Bright day with sun at +Y [default]") profiles.add_item("Bright day with sun at -Y") profiles.add_item("Bright day with sun at +Z") profiles.add_item("Less bright day with sun at +Y") profiles.add_item("Less bright day with sun at -Y") profiles.add_item("Less bright day with sun at +Z") profiles.add_item("Cloudy day (no direct sun)") profiles.add_item("Custom") view_ctrls.add_fixed(separation_height) view_ctrls.add_child(gui.Label("Lighting profiles")) view_ctrls.add_child(profiles) self._settings_panel.add_fixed(separation_height) self._settings_panel.add_child(view_ctrls) advanced = gui.CollapsableVert("Advanced lighting", 0, gui.Margins(em, 0, 0, 0)) self._show_skybox = gui.Checkbox("HDR map") self._show_skybox.checked = True self._show_sunlight = gui.Checkbox("Sun") self._show_sunlight.checked = True advanced.add_child(gui.Label("Light sources")) h = gui.Horiz(em) h.add_child(self._show_skybox) h.add_child(self._show_sunlight) advanced.add_child(h) self._ibl_map = gui.Combobox() self._ibl_map.add_item("default") self._ibl_intensity = gui.Slider(gui.Slider.INT) self._ibl_intensity.set_limits(0, 200000) self._ibl_intensity.int_value = 45000 grid = gui.VGrid(2, 0.25 * em) grid.add_child(gui.Label("HDR map")) grid.add_child(self._ibl_map) grid.add_child(gui.Label("Intensity")) grid.add_child(self._ibl_intensity) advanced.add_fixed(separation_height) advanced.add_child(gui.Label("Environment")) advanced.add_child(grid) self._sun_intensity = gui.Slider(gui.Slider.INT) self._sun_intensity.set_limits(0, 200000) self._sun_intensity.int_value = 45000 self._sun_dir = gui.VectorEdit() self._sun_dir.vector_value = [0.577, -0.577, -0.577] self._sun_color = gui.ColorEdit() self._sun_color.color_value = gui.Color(1, 1, 1, 1) grid = gui.VGrid(2, 0.25 * em) grid.add_child(gui.Label("Intensity")) grid.add_child(self._sun_intensity) grid.add_child(gui.Label("Direction")) grid.add_child(self._sun_dir) grid.add_child(gui.Label("Color")) grid.add_child(self._sun_color) advanced.add_fixed(separation_height) advanced.add_child(gui.Label("Sun (Directional light)")) advanced.add_child(grid) self._settings_panel.add_fixed(separation_height) self._settings_panel.add_child(advanced) material_settings = gui.CollapsableVert("Material settings", 0, gui.Margins(em, 0, 0, 0)) self._shader = gui.Combobox() self._shader.add_item("Lit") self._shader.add_item("Unlit") self._shader.add_item("Normals") self._shader.add_item("Depth") self._material_profile = gui.Combobox() self._material_profile.add_item("Clay") self._material_profile.add_item("Glazed ceramic") self._material_profile.add_item("Metal (rougher)") self._material_profile.add_item("Metal (smoother)") self._material_profile.add_item("Plastic") self._material_profile.add_item("Polished ceramic [default]") self._material_color = gui.ColorEdit() self._material_color.color_value = gui.Color(1, 1, 1, 1) self._point_size = gui.Slider(gui.Slider.INT) self._point_size.set_limits(1, 10) self._point_size.int_value = 3 grid = gui.VGrid(2, 0.25 * em) grid.add_child(gui.Label("Type")) grid.add_child(self._shader) grid.add_child(gui.Label("Material")) grid.add_child(self._material_profile) grid.add_child(gui.Label("Color")) grid.add_child(self._material_color) grid.add_child(gui.Label("Point size")) grid.add_child(self._point_size) material_settings.add_child(grid) self._settings_panel.add_fixed(separation_height) self._settings_panel.add_child(material_settings) # ---- # Normally our user interface can be children of all one layout (usually # a vertical layout), which is then the only child of the window. In our # case we want the scene to take up all the space and the settings panel # to go above it. We can do this custom layout by providing an on_layout # callback. The on_layout callback should set the frame # (position + size) of every child correctly. After the callback is # done the window will layout the grandchildren. w.set_on_layout(self._on_layout) w.add_child(self._scene) w.add_child(self._settings_panel) # ---- Menu ---- # The menu is global (because the macOS menu is global), so only create # it once, no matter how many windows are created if gui.Application.instance.menubar is None: if isMacOS: app_menu = gui.Menu() app_menu.add_item("About", AppWindow.MENU_ABOUT) app_menu.add_separator() app_menu.add_item("Quit", AppWindow.MENU_QUIT) file_menu = gui.Menu() file_menu.add_item("Open...", AppWindow.MENU_OPEN) file_menu.add_item("Export Current Image...", AppWindow.MENU_EXPORT) file_menu.set_enabled(AppWindow.MENU_EXPORT, False) if not isMacOS: file_menu.add_separator() file_menu.add_item("Quit", AppWindow.MENU_QUIT) settings_menu = gui.Menu() settings_menu.add_item("Lighting & Materials", AppWindow.MENU_SHOW_SETTINGS) settings_menu.set_checked(AppWindow.MENU_SHOW_SETTINGS, True) help_menu = gui.Menu() help_menu.add_item("About", AppWindow.MENU_ABOUT) menu = gui.Menu() if isMacOS: # macOS will name the first menu item for the running application # (in our case, probably "Python"), regardless of what we call # it. This is the application menu, and it is where the # About..., Preferences..., and Quit menu items typically go. menu.add_menu("Example", app_menu) menu.add_menu("File", file_menu) menu.add_menu("Settings", settings_menu) # Don't include help menu unless it has something more than # About... else: menu.add_menu("File", file_menu) menu.add_menu("Settings", settings_menu) menu.add_menu("Help", help_menu) gui.Application.instance.menubar = menu # The menubar is global, but we need to connect the menu items to the # window, so that the window can call the appropriate function when the # menu item is activated. w.set_on_menu_item_activated(AppWindow.MENU_OPEN, self._on_menu_open) w.set_on_menu_item_activated(AppWindow.MENU_QUIT, self._on_menu_quit) w.set_on_menu_item_activated(AppWindow.MENU_SHOW_SETTINGS, self._on_menu_toggle_settings_panel) w.set_on_menu_item_activated(AppWindow.MENU_ABOUT, self._on_menu_about)