Управление материалами
Changing parameters of the material assigned to the object surface via code, and replacing one assigned material with another.Изменение параметров материала, назначенного на поверхность объекта из кода, а также замена самого материала на другой.
Materials can be operated not only in the Editor — sometimes it is required to assign materials via code (in case of procedural content generation, for example) or configure some of their parameters. To control materials via API, we use the following two classes:С материалами можно работать не только в Редакторе, иногда бывает нужно назначать материалы из кода (при процедурной генерации контента, например) или менять какие-то их параметры. Для управления материалами через API мы используем следующие два класса:
- Materials class that represents an interface for managing loaded materials (this is a manager class that can help you find a required material, for example).Materials, который представляет интерфейс для управления загруженными материалами (это класс-менеджер, с его помощью можно, к примеру, отыскать нужный материал).
- Material class that is used to manage each individual material.Material, который используется для управления конкретным материалом.
The following example demonstrates how to inherit a new material from the base one, which is called mesh_base.Следующий пример показывает как унаследовать новый материал от базового, который называется mesh_base.
#include <UnigineMaterials.h>
#include <UnigineObjects.h>
#include<UniginePrimitives.h>
using namespace Unigine;
/* .. */
int AppWorldLogic::init()
{
// создаем куб (ObjectMeshDynamic node)
ObjectMeshDynamicPtr my_mesh = Primitives::createBox(vec3(1.5f, 1.5f, 1.5f));
// находим материал с именем mesh_base, от которого будем наследоваться
MaterialPtr mesh_base = Materials::findManualMaterial("Unigine::mesh_base");
// наследуем от него дочерний материал
MaterialPtr my_mesh_base = mesh_base->inherit();
// сохраняем дочерний материал в файл "materials/my_mesh_base0.mat" (до сохранения
// такой материал существует только в оперативной памяти и удаляется после завершения работы приложения)
my_mesh_base->createMaterialFile("materials/my_mesh_base0.mat");
// устанавливаем множитель цвета альбедо для материала в красный
my_mesh_base->setParameterFloat4("albedo_color", Math::vec4(255, 0, 0, 255));
// назначаем материал "my_mesh_base0.mat" первой поверхности (с индексом 0) объекта my_mesh (ObjectMeshDynamiс)
my_mesh->setMaterialPath("materials/my_mesh_base0.mat", 0);
// назначаем материал "my_mesh_base0.mat" всем поверхностям объекта my_mesh (ObjectMeshDynamiс)
my_mesh->setMaterialPath("materials/my_mesh_base0.mat", "*");
}
int AppWorldLogic::shutdown()
{
// удаляем материал "materials/my_mesh_base0.mat"
Materials::removeMaterial(Materials::findMaterialByPath("materials/my_mesh_base0.mat")->getGUID());
return 1;
}
PracticeПрактика#
Now let's create an interactive poster in our interior with an ability to change its albedo texture and apply a light filter to the picture (add a tone).Теперь давайте добавим в наш интерьер интерактивный постер, который будет иметь возможность изменения текстуру альбедо и наложения на картинку светофильтра (добавление тона).
First, we're gonna need a Static Mesh plane.Для начала нам понадобится плоскость (Static Mesh).
- Go to the archviz/textures folder and find the plane.mesh asset.Откройте в Ассет Браузере папку archviz/textures и найдите в ней ассет plane.mesh.
- Drag it to the scene (a new Static Mesh object will be created) and change its name to "poster".Перетащите ассет на сцену (будет создан новый объект Static Mesh и переименуйте его в "poster".
-
Set poster's transformation as shown on the image below:Измените положение и поворот постера, как показано на рисунке:
- In the Surface Material section create a child material for the surface (click create a child material) to be able to change its parameters and drag the tex01.jpg asset to the Albedo field in the Textures tab.В группе Surface Material отнаследуйте для поверхности новый материал (щелкните create a child material), чтобы иметь возможность изменять его параметры, затем перетащите ассет tex01.jpg в поле Albedo на вкладке Textures.
Let's create the Customizable component (inherited from Interactable) that switches textures from the list (the array parameter) on the object — Action(0), and changes the albedo color multiplier by overrriding the method — Action(1). The code of the component looks like this:Постер готов, теперь давайте создадим компонент Customizable (наследник Interactable), переключающий на объекте текстуры из списка (array parameter) Action(0) и меняющий множитель цвета albedo через перегрузку метода Action(1). Код компонента выглядит так:
#pragma once
#include <UnigineComponentSystem.h>
#include "Interactable.h"
class Customizable :
public Interactable
{
public:
// Объявляем конструктор и деструктор для нашего класса, а также задаем имя связанного с компонентом свойства (property).
// Файл Customizable.prop со всеми описанными ниже параметрами будет сгенерирован Компонентной системой в папке 'data' вашего проекта при первом запуске приложения
COMPONENT_DEFINE(Customizable, Interactable);
// объявляем параметры компонента и задаем начальные значения
PROP_ARRAY(File, textures);
// регистрация методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения (сами методы объявляются в protected-блоке ниже)
COMPONENT_INIT(init);
// перегрузка метода Action для дочернего компонента
void action(int num = 0);
protected:
// объявление методов, которые будут вызываться на соответствующих этапах жизненного цикла приложения
void init();
private:
int current_texture = 0; // текущая текстура
};
#include "Customizable.h"
// Регистрация компонента Customizable
REGISTER_COMPONENT(Customizable);
using namespace Unigine;
using namespace Math;
void Customizable::init()
{
// задаем текст подсказки, которая будет отображаться при наведении курсора на объект
tooltip = "По правому щелчку мыши циклически переключает материалы на объекте по списку. По клавише 'TAB' случайным образом меняет цветовой тон.";
}
// перегрузка действия для дочернего компонента
void Customizable::action(int num)
{
Unigine::ObjectPtr object = checked_ptr_cast<Unigine::Object>(node);
// выбор действия
switch (num)
{
// циклическая смена текстур альбедо в материале объекта из указанного списка
case 0:
// если список текстур не задан или пуст, ничего не делаем
if (textures.nullCheck() || textures.size() < 0)
return;
current_texture++;
if (current_texture >= textures.size())
current_texture = 0;
object->setMaterialTexture("albedo", Unigine::FileSystem::guidToPath(FileSystem::getGUID(textures[current_texture].getRaw())), 0);
break;
// смена множителя цвета albedo для текущего материала на объекте на произвольный цвет
case 1:
object->getMaterial(0)->setParameterFloat4("albedo_color", Math::randColor());
break;
}
}
Let's save our files and then build and run our application by hitting Ctrl + F5 to make the Component System generate a property to be used to assign our component to nodes. Close the application after running it and switch to UnigineEditor.Сохраним файлы, а затем соберем и запустим приложение нажав Ctrl + F5, чтобы Компонентная система сгенерировала property для связи компонента с нодой. После запуска приложения закроем его и вернемся в UnigineEditor.
Then let's assign our component to the poster node and fill the texture array (tex01, tex02, tex03).И, наконец, назначим наш компонент на ноду poster и заполним массив текстур (tex01, tex02, tex03).
Now the image on the poster can be changed in one click.Теперь на стене у нас постер, изображение на котором можно сменить в один клик.