Пользовательский интерфейс
In UNIGINE a Graphical User Interface (GUI) is composed of different types of widgets added to it. Basically, there are two ways of creating GUI:В UNIGINE графический пользовательский интерфейс (GUI) состоит из добавленных к нему виджетов различных типов. Cуществует два основных способа создания графического интерфейса:
- By adding widgets to the system GUI (UNIGINE user interface) that is rendered on top of application window. In this case we use the Gui class.Добавление виджетов в системный графический интерфейс (UNIGINE Gui), который отображается поверх окна приложения. В этом случае мы используем класс Gui.
- By adding widgets to a GUI object positioned in the world. In this case, any postprocessing filter can be applied. By creating a specific Gui object (or GuiMesh for arbitrary geometry) that can be placed anywhere in the scene, and adding widgets to it. This can be useful, for example, to implement interaction with the interface displayed on a computer screen in a room (i.e. UI bound to an object that can be viewed from different angles). In this case, a post-processing filter can be applied.Создание отдельного объекта Gui (или GuiMesh для произвольной геометрии), который можно расположить где угодно в сцене, и добавления виджетов к нему. Это может пригодиться, к примеру, чтобы реализовать взаимодействие с интерфейсом, отображаемым на экране компьютера в помещении (т.е. UI с привязкой к объекту, на который можно посмотреть под разным углом). В этом случае может быть применен любой фильтр постобработки.
There are 2 ways to create the GUI layout:Существует 2 способа создания макета графического интерфейса:
- Directly from code via GUI classesНепосредственно из кода через GUI-классы.
- Using UI files with the description of user interface. Such a description file in XML-like format can be created for a complex interface to write less code.С помощью ui-файлов с описанием пользовательского интерфейса. Такой файл описания в xml-подобном формате можно подготовить для сложного интерфейса, чтобы писать меньше кода.
The following code demonstrates how to add Label and Slider widgets to the system GUI:Следующий код демонстрирует, как добавить виджеты Label и Slider в системный графический интерфейс:
// получаем ссылку на системный GUI
Gui gui = Gui.GetCurrent();
// создаем виджет Label и устанавливаем его параметры
WidgetLabel widget_label = new WidgetLabel(gui, "Label text:");
widget_label.SetToolTip("This is my label!");
widget_label.Arrange();
widget_label.SetPosition(10, 10);
// создаем виджет Slider и устанавливаем его параметры
WidgetSlider widget_slider = new WidgetSlider(gui, 0, 360, 90);
widget_slider.SetToolTip("This is my slider!");
widget_slider.Arrange();
widget_slider.SetPosition(100, 10);
// добавляем виджеты к системному GUI
gui.AddChild(widget_label, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
gui.AddChild(widget_slider, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
In order to use GUI elements (not just watch them rendered) we must specify handlers for various events (click, change, etc.). The following code demonstrates how to set event handlers:Чтобы элементы графического интерфейса не просто рисовались, а работали, нужно указать обработчики для различных событий (щелчок, изменение и т.д.). Пример ниже показывает, как установить обработчики событий:
void onSliderChanged(Widget sender)
{
Log.Message("\n The value of the slider has been changed: {0}\n", (sender as WidgetSlider).Value);
}
private void Init()
{
// получаем ссылку на системный GUI
Gui gui = Gui.GetCurrent();
// создаем виджет Button и устанавливаем его параметры
WidgetButton widget_button = new WidgetButton(gui, "Нажми меня");
widget_button.Arrange();
widget_button.SetPosition(10,10);
// создаем виджет Slider и устанавливаем его параметры
WidgetSlider widget_slider = new WidgetSlider(gui);
widget_slider.Arrange();
widget_slider.SetPosition(100,10);
// устанавливаем лямбда-функцию для обработки события CLICKED (щелчок мыши)
widget_button.EventClicked.Connect(() => Log.Message("Кнопка нажата\n"));
// устанавливаем обработчик для события CHANGED (изменение)
widget_slider.EventChanged.Connect(onSliderChanged);
// добавляем созданные виджеты к системному GUI
gui.AddChild(widget_button, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
gui.AddChild(widget_slider, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
}
PracticeПрактика#
In architectural visualization projects, a widespread option is changing materials on various objects, for example, to preview different wallpapers on the walls and match them with the decor of the furniture. For our project, let's create a component (also inherit it from Interactable) that displays a list of available materials for a selected object in the UI based on ObjectGui with the ability to select and automatically apply them.В проектах архитектурной визуализации часто добавляют возможность изменения материала на различных объектах, например, чтобы посмотреть, как будут выглядеть стены с разными обоями, а заодно и подобрать к ним декор гарнитура. Для нашего проекта напишем компонент (также унаследуем его от Interactable) отображающий в UI на основе ObjectGui список доступных материалов для выделенного объекта с возможностью выбора и автоматического применения.
-
Create a new component called MaterialCustomizer and add the following code to it:Создадим новый компонент и назовем его MaterialCustomizer, добавим в него следующий код:
using System; using System.Collections; using System.Collections.Generic; using Unigine; [Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- идентификатор генерируется автоматически для нового компонента public class MaterialCustomizer : Interactable { [Parameter(Tooltip = "Список материалов для кастомизации объекта")] public List<Material> MaterialsList = null; private ObjectGui gui = null; // объект GUI для отображения интерфейса выбора материала // функция, применяющая выбранный в меню материал к выделенной поверхности кастомизируемого объекта private void select_material_handler(Widget w) { (node as Unigine.Object).SetMaterial(MaterialsList[(w as WidgetComboBox).CurrentItem],ComponentSystem.FindComponentInWorld<InputProcessor>().intersection.Surface); } private void Init() { // задаем текст подсказки, которая будет отображаться при наведении курсора на объект tooltip = "По правому щелчку мыши отображается меню, в котором можно выбрать материал для объекта."; // создаем объект GUI для отображения интерфейса выбора материала и задаем его размеры и разрешение gui = new ObjectGui(0.5f, 0.5f); gui.SetScreenSize(600, 600); // включаем обнаружение пересечений, для взаимодействия с UI при помощи мыши gui.SetIntersection(true, 0); // делаем так, чтобы интерфейс всегда поворачивался к пользователю и не загораживался другими объектами gui.Billboard = true; gui.GetMaterialInherit(0).DepthTest = false; // отключаем черный фон и временно скрываем UI gui.Background = false; gui.Enabled = false; // задаем дистанцию, с которой возможно взаимодействие с интерфейсом gui.ControlDistance = 10; if(MaterialsList != null && MaterialsList.Count > 0) { // добавляем виджет-контейнер WidgetVBox для вертикальной компоновки элементов, устанавливаем отступы WidgetVBox vbox = new WidgetVBox(gui.GetGui()); vbox.SetSpace(20,20); // включаем фон и задаем его цвет vbox.Background = 1; vbox.BackgroundColor = new vec4(0.1f,0.5f,0.1f,0.4f); // создаем виджет WidgetLabel для отображения заголовка, устанавливаем его положение размер шрифта WidgetLabel label = new WidgetLabel(gui.GetGui(), "Выберите материал:"); label.FontSize = 50; // добавляем виджет Label в контейнер vbox.AddChild(label,Gui.ALIGN_TOP); // создаем виджет WidgetComboBox для отображения выпадающего списка материалов, WidgetComboBox mat_menu = new WidgetComboBox(gui.GetGui()); mat_menu.FontSize = 40; // устанавливаем колбэк на выбор элемента из списка mat_menu.EventChanged.Connect(select_material_handler); // добавляем элементы в меню в соответствии со списком материалов for(int i = 0; i < MaterialsList.Count; i++) { string str = FileSystem.GetVirtualPath(MaterialsList[i].Path); mat_menu.AddItem(str.Substring(str.LastIndexOf("/")+1)); } // добавляем виджет ComboBox в контейнер vbox.AddChild(mat_menu,Gui.ALIGN_TOP); // добавляем виджет-контейнер в GUI gui.GetGui().AddChild(vbox,Gui.ALIGN_EXPAND|Gui.ALIGN_OVERLAP); } } public override void Action(int num) { // индексы действий отличные от нуля для данного компонента невалидны, поэтому игнорируются if (num != 0) return; // располагаем интерфейс в точке на кастомизируемом объекте, где была нажата правая клавиша мыши gui.WorldPosition = ComponentSystem.FindComponentInWorld<InputProcessor>().intersection.Point; // скрываем интерфейс выбора материала для остальных объектов foreach(MaterialCustomizer customizer in ComponentSystem.FindComponentsInWorld<MaterialCustomizer>() ) if (this != customizer) customizer.gui.Enabled = false; // отображаем или скрываем интерфейс выбора материала для данного объекта gui.Enabled = !gui.Enabled; } }
- Assign our new component to the bedside_table_1 object in our scene.Назначим компонент на объект bedside_table_1 в нашей сцене.
-
Fill in the list of materials. To do this, change the number of items in the list from 0 to 3 and then drag three materials into the corresponding fields.Затем заполним список материалов. Для этого изменим количество элементов в списке с 0 на 3 и после этого перетащим три материала в соответствующие поля.
Upon right-clicking an object a list of available materials will be displayed, you can choose the desired one, and it will be applied automatically right as you click it:При нажатии правой кнопки мыши будет отображаться список доступных материалов, в котором щелчком левой кнопки можно выбрать нужный и он применится автоматически: