Видеоуроки
Interface
Essentials
Advanced
Подсказки и советы
Программирование на C#
Рендеринг
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Настройки и предпочтения
Работа с проектами
Настройка параметров узла
Setting Up Materials
Setting Up Properties
Освещение
Landscape Tool
Sandworm
Использование инструментов редактора для конкретных задач
Extending Editor Functionality
Встроенные объекты
Узлы (Nodes)
Объекты (Objects)
Эффекты
Decals
Light Sources
Geodetics
World Objects
Sound Objects
Pathfinding Objects
Players
Программирование
Основы
Настройка среды разработки
Примеры использования
UnigineScript
C++
C#
File Formats
Rebuilding the Engine Tools
GUI
Двойная точность координат
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Art Samples
Tutorials

Создание пользовательского шейдера для отложенного прохода рендеринга

In UNIGINE all the opaque geometry is rendered in the deferred rendering pass. This article explains how to create your own material with shaders (both vertex and fragment) for the deferred rendering pass. В UNIGINE вся непрозрачная геометрия визуализируется в проходе отложенной визуализации . В этой статье объясняется, как создать свой собственный материал с помощью шейдеров (как вершинных, так и фрагментных) для этапа отложенного рендеринга.

In this article, we create a material for static, dynamic and skinned meshes. We define a heightmap for the vertex shader and an albedo texture for the fragment shader. Also, we calculate normals to ensure proper lighting for our mesh. В этой статье мы создаем материал для статических, динамических и скелетных мешей. Мы определяем карту высот для вершинного шейдера и текстуру альбедо для фрагментного шейдера. Кроме того, мы вычисляем нормали, чтобы обеспечить правильное освещение для нашей сетки.

See AlsoСмотрите также#

Create a MaterialСоздаем материал#

The material is the essential thing for rendering: you specify shaders, states, bindings, textures in the material, thus, telling the engine how to render it. Материал - это важная вещь для рендеринга: вы указываете шейдеры, состояния, привязки, текстуры в материале, тем самым сообщая движку, как его рендерить.

Let's create our own ULON-based base material (for deferred pass only) and write the vertex and the fragment shaders for it. Perform the following steps to create the material: Давайте создадим наш собственный ULON-based base material (for deferred pass only) and write the vertex and the fragment shaders for it. Perform the following steps to create the material:

  1. In your project folder open the data/materials folder. В папке проекта откройте папку data/materials.
  2. Create a new custom_mesh_material.basemat file and implement the following base material:
    Source Code (ULON)
    // describing the read-only custom mesh material to be used for static meshes, 
    // setting prefixes to be used in shaders to refer to textures and parameters 
    BaseMaterial custom_mesh_material <node=ObjectMeshStatic editable=false var_prefix=var texture_prefix=tex>
    {
    	// enabling the deferred pass for our material and hiding it (will be invisible in the UnigineEditor)
    	State deferred=1	<internal=true>
    
    	//////////////////////////////////////////////////////////////////////////
    	// Passes
    	//////////////////////////////////////////////////////////////////////////
    
    	// describing the deferred pass with links to shaders to be used
    	Pass deferred <defines="BASE_DEFERRED">
    	{
    		Vertex   = "shaders/vertex/deferred.vert"
    		Fragment = "shaders/fragment/deferred.frag"
    	}
    	
    	// describing bindings for node types to which the material is to be applicable
    	Bind ObjectMeshStatic=ObjectMeshDynamic
    	Bind ObjectMeshStatic=ObjectMeshSkinned
    }
    • We defined a new custom_mesh_material base material with the deferred state (internal).We defined a new custom_mesh_material base material with the deferred state (internal).
    • Also we defined shaders (fragment and vertex) for the deferred pass and set the paths to them (we will create both these shader files and a folder in the following sections).Also we defined shaders (fragment and vertex) for the deferred pass and set the paths to them (we will create both these shader files and a folder in the following sections).
    • Finally, we defined the bindings: types of meshes for which the material can be assigned.Finally, we defined the bindings: types of meshes for which the material can be assigned.
    We defined a new custom_mesh_material base material with the deferred state (internal).Also we defined shaders (fragment and vertex) for the deferred pass and set the paths to them (we will create both these shader files and a folder in the following sections).Finally, we defined the bindings: types of meshes for which the material can be assigned.
    Создайте новый файл custom_mesh_material.basemat и примените следующий базовый материал:
    Source Code (ULON)
    // describing the read-only custom mesh material to be used for static meshes, 
    // setting prefixes to be used in shaders to refer to textures and parameters 
    BaseMaterial custom_mesh_material <node=ObjectMeshStatic editable=false var_prefix=var texture_prefix=tex default=true>
    {
    	// enabling the deferred pass for our material and hiding it (will be invisible in the UnigineEditor)
    	State deferred=1	<internal=true>
    
    	//////////////////////////////////////////////////////////////////////////
    	// Passes
    	//////////////////////////////////////////////////////////////////////////
    
    	// describing the deferred pass with links to shaders to be used
    	Pass deferred <defines="BASE_DEFERRED">
    	{
    		Vertex   = "shaders/vertex/deferred.vert"
    		Fragment = "shaders/fragment/deferred.frag"
    	}
    	
    	// describing bindings for node types to which the material is to be applicable
    	Bind ObjectMeshStatic=ObjectMeshDynamic
    	Bind ObjectMeshStatic=ObjectMeshSkinned
    }
    • We defined a new custom_mesh_material base material with the deferred state (internal). Мы определили новый базовый материал custom_mesh_material с отложенным (внутренним) состоянием.
    • Also we defined shaders (fragment and vertex) for the deferred pass and set the paths to them (we will create both these shader files and a folder in the following sections). Также мы определили шейдеры (фрагмент и вершину) для отложенного прохода и установили пути к ним (мы создадим оба этих файла шейдеров и папку в следующих разделах).
    • Finally, we defined the bindings: types of meshes for which the material can be assigned. Наконец, мы определили привязки: типы сеток, для которых может быть назначен материал.
  3. Save the changes. Сохраните изменения.

Create a Vertex ShaderСоздаем вершинный шейдер#

In this section, we shall explain how to create the structure for shaders and how to create the custom vertex shader. В этом разделе мы объясним, как создать структуру для шейдеров и как создать собственный вершинный шейдер.

We're gonna need to create two shaders for our material: vertex and fragment. To create a vertex shader, perform the following: Нам понадобится создать два шейдера для нашего материала: вершинный и фрагментный. Чтобы создать вершинный шейдер, выполните следующие действия:

  1. Create the shaders folder in your project's /data folder. Создайте папку shaders в папке /data вашего проекта.
  2. Inside the shaders folder, create two folders: vertex for vertex shaders, fragment for fragment shaders. Внутри папки shaders создайте две папки: vertex для вершинных шейдеров, fragment для шейдеров фрагментов.
  3. Open a plain text editor and write the following:
    Source code (UUSL)
    // Include Unified Unigine Shader Language (UUSL) header
    #include <core/shaders/common/common.h>
    
    // Input data struct
    STRUCT(VERTEX_IN)
    	INIT_ATTRIBUTE(float4,0,POSITION)	// Vertex position
    	INIT_ATTRIBUTE(float4,1,TEXCOORD0)	// Vertex texcoord (uv)
    	INIT_ATTRIBUTE(float4,2,TEXCOORD1)	// Vertex basis tangent
    	INIT_ATTRIBUTE(float4,3,TEXCOORD2)	// Vertex color
    	INIT_INSTANCE
    END
    
    // Our output vertex data struct
    STRUCT(VERTEX_OUT)
    	INIT_POSITION					// Out projected position
    	INIT_OUT(float4,0)				// Texcoord (uv)
    END
    
    MAIN_BEGIN(VERTEX_OUT,VERTEX_IN)
    	
    	// Get transform with scale and rotation (without translation)
    	float4x4 transform = getObjectTransform(IN_INSTANCE);
    	float4 row_0 = transform[0];
    	float4 row_1 = transform[1];
    	float4 row_2 = transform[2];
    	
    	// Get Modelview-space transform
    	float4 in_vertex = float4(IN_ATTRIBUTE(0).xyz,1.0f);
    	float4 position = mul4(row_0,row_1,row_2,in_vertex);
    	
    	// Set output UV
    	float4 texcoord = IN_ATTRIBUTE(1);
    	OUT_DATA(0) = texcoord;
    	
    	// Set output position
    	OUT_POSITION = getPosition(position);
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).You should add a new line (press Enter) after closing the instruction (after MAIN_END command).

    The code is pretty simple and clear. In the code above weThe code is pretty simple and clear. In the code above we

    • Include the UUSL header.Include the UUSL header.
    • Define the input vertex data structure.Define the input vertex data structure.
    • Define the output vertex data structure.Define the output vertex data structure.
    • Start the main program of the shader:
      • Translate the object-space coordinates to clipping space coordinates.Translate the object-space coordinates to clipping space coordinates.
      • Set the output UV.Set the output UV.
      • Set the vertex position.Set the vertex position.
      Translate the object-space coordinates to clipping space coordinates.Set the output UV.Set the vertex position.
      Start the main program of the shader:
      • Translate the object-space coordinates to clipping space coordinates.Translate the object-space coordinates to clipping space coordinates.
      • Set the output UV.Set the output UV.
      • Set the vertex position.Set the vertex position.
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).The code is pretty simple and clear. In the code above weInclude the UUSL header.Define the input vertex data structure.Define the output vertex data structure.Start the main program of the shader:
    • Translate the object-space coordinates to clipping space coordinates.Translate the object-space coordinates to clipping space coordinates.
    • Set the output UV.Set the output UV.
    • Set the vertex position.Set the vertex position.
    Translate the object-space coordinates to clipping space coordinates.Set the output UV.Set the vertex position.
    Откройте обычный текстовый редактор и напишите следующее:
    Source code (UUSL)
    // Include Unified Unigine Shader Language (UUSL) header
    #include <core/shaders/common/common.h>
    
    // Input data struct
    STRUCT(VERTEX_IN)
    	INIT_ATTRIBUTE(float4,0,POSITION)	// Vertex position
    	INIT_ATTRIBUTE(float4,1,TEXCOORD0)	// Vertex texcoord (uv)
    	INIT_ATTRIBUTE(float4,2,TEXCOORD1)	// Vertex basis tangent
    	INIT_ATTRIBUTE(float4,3,TEXCOORD2)	// Vertex color
    	INIT_INSTANCE
    END
    
    // Our output vertex data struct
    STRUCT(VERTEX_OUT)
    	INIT_POSITION					// Out projected position
    	INIT_OUT(float4,0)				// Texcoord (uv)
    END
    
    MAIN_BEGIN(VERTEX_OUT,VERTEX_IN)
    	
    	// Get transform with scale and rotation (without translation)
    	float4x4 transform = getObjectTransform(IN_INSTANCE);
    	float4 row_0 = transform[0];
    	float4 row_1 = transform[1];
    	float4 row_2 = transform[2];
    	
    	// Get Modelview-space transform
    	float4 in_vertex = float4(IN_ATTRIBUTE(0).xyz,1.0f);
    	float4 position = mul4(row_0,row_1,row_2,in_vertex);
    	
    	// Set output UV
    	float4 texcoord = IN_ATTRIBUTE(1);
    	OUT_DATA(0) = texcoord;
    	
    	// Set output position
    	OUT_POSITION = getPosition(position);
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command). Вам следует добавить новую строку (нажмите Enter) после закрытия инструкции (после командыMAIN_END).

    The code is pretty simple and clear. In the code above weКод довольно простой и понятный. В приведенном выше коде мы

    • Include the UUSL header. Включите заголовок UUSL.
    • Define the input vertex data structure. Определите структуру данных входной вершины.
    • Define the output vertex data structure. Определите структуру данных выходной вершины.
    • Start the main program of the shader:
      • Translate the object-space coordinates to clipping space coordinates.Translate the object-space coordinates to clipping space coordinates.
      • Set the output UV.Set the output UV.
      • Set the vertex position.Set the vertex position.
      Translate the object-space coordinates to clipping space coordinates.Set the output UV.Set the vertex position.
      Запустите основную программу шейдера:
      • Translate the object-space coordinates to clipping space coordinates. Преобразуйте координаты пространства объекта в координаты пространства отсечения.
      • Set the output UV. Установите выходной UV.
      • Set the vertex position. Установите положение вершины.
  4. Save the shader file with the deferred.vert name and extension inside the data/shaders/vertex folder. Сохраните файл шейдера с именем и расширением deferred.vert в папке data/shaders/vertex.

Create a Fragment ShaderСоздаем фрагментный шейдер#

This section contains instructions on how to create a fragment shader (also known as pixel shader). В этом разделе содержатся инструкции по созданию фрагментного шейдера (также известного как пиксельный шейдер ).

To create a fragment shader, perform the following: Чтобы создать фрагментный шейдер, выполните следующие действия:

  1. Open a plain text editor and write the following:
    Source code (UUSL)
    // Include the UUSL language header
    #include <core/shaders/common/fragment.h>
    
    // Input data struct
    STRUCT(FRAGMENT_IN)
    	INIT_POSITION				// Projected position
    	INIT_IN(float4,0)			// Texcoord (uv)
    END
    
    MAIN_BEGIN_DEFERRED(FRAGMENT_IN)
    	
    	// Create the G-Buffer and set it
    	GBuffer gbuffer = GBufferDefault();
    	
    	setGBuffer(gbuffer);
    	
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).You should add a new line (press Enter) after closing the instruction (after MAIN_END command).

    Explanations on fragment shader:Explanations on fragment shader:

    • We include the UUSL header for fragment shaders.We include the UUSL header for fragment shaders.
    • Define the input fragment data struct (where we receive the data from output structure of the vertex shader).Define the input fragment data struct (where we receive the data from output structure of the vertex shader).
    • Start the main program of the shader, where we create a GBuffer instance for metalness workflow and set it. Start the main program of the shader, where we create a GBuffer instance for metalness workflow and set it.
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).Explanations on fragment shader:We include the UUSL header for fragment shaders.Define the input fragment data struct (where we receive the data from output structure of the vertex shader).Start the main program of the shader, where we create a GBuffer instance for metalness workflow and set it.
    Откройте обычный текстовый редактор и напишите следующее:
    Source code (UUSL)
    // Include the UUSL language header
    #include <core/shaders/common/fragment.h>
    
    // Input data struct
    STRUCT(FRAGMENT_IN)
    	INIT_POSITION				// Projected position
    	INIT_IN(float4,0)			// Texcoord (uv)
    END
    
    MAIN_BEGIN_DEFERRED(FRAGMENT_IN)
    	
    	// Create the G-Buffer and set it
    	GBuffer gbuffer = GBufferDefault();
    	
    	setGBuffer(gbuffer);
    	
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command). Вам следует добавить новую строку (нажмите Enter) после закрытия инструкции (после командыMAIN_END).

    Explanations on fragment shader:Пояснения к фрагментному шейдеру:

    • We include the UUSL header for fragment shaders. Мы включаем заголовок UUSL для фрагментных шейдеров.
    • Define the input fragment data struct (where we receive the data from output structure of the vertex shader). Определите структуру данных входного фрагмента (куда мы получаем данные из выходной структуры вершинного шейдера).
    • Start the main program of the shader, where we create a GBuffer instance for metalness workflow and set it. Запустите основную программу шейдера, где мы создаем экземпляр GBufferдля рабочего процесса metalness и устанавливаем его.
  2. Save the shader file with the deferred.frag name and extension to the data/shaders/fragment folder. Сохраните файл шейдера с именем и расширением deferred.frag в папку data/shaders/fragment.

Working with MaterialРабота с материалом#

After performing all these steps you can see the recently created shaders in use. They are primitive, and don't provide a nice final image. Anyway, to check their work perform the following steps: После выполнения всех этих шагов вы можете увидеть, что недавно созданные шейдеры используются. Они примитивны и не дают хорошего финального изображения. В любом случае, чтобы проверить их работу, выполните следующие действия:

  1. Open your world by using UnigineEditor, The Editor will create all necessary resources in the data folder. Откройте свой мир с помощью UnigineEditor. Редактор создаст все необходимые ресурсы в папке data.
  2. Open the Materials Hierarchy window. You will see the recently created base material in the hierarchy. Откройте окно Materials Hierarchy. Вы увидите недавно созданный базовый материал в иерархии.
  3. Assign the created material to the material ball by dragging it to the object. Or create a primitive (e.g., a sphere) and assign the material to the primitive. Назначьте созданный материал материальному шару, перетащив его на объект. Или создайте примитив (например, сферу) и назначьте материал примитиву.

After that you'll get the following result: После этого вы получите следующий результат:

It doesn't look super good, but it works. Выглядит не очень хорошо, но работает.

Let's go further and calculate the tangent basis for the mesh and assign textures to it. Пойдем дальше и вычислим касательную основу для меша и назначим ему текстуры.

Adding Textures to ShadersДобавление текстур в шейдеры#

Let's add textures to both shaders: vertex and fragment. In the vertex shader we will use a texture as a displacement map and in the fragment shader as an albedo map. Давайте добавим текстуры в оба шейдера: вершинный и фрагментный. В вершинном шейдере мы будем использовать текстуру в качестве карты смещения, а во фрагменте - карту альбедо.

Editing the MaterialРедактирование материала#

First, let's edit our custom base material and add two texture slots and a parameter to control displacement. Во-первых, давайте отредактируем наш собственный базовый материал и добавим два слота для текстур и параметр для управления смещением.

  1. Open the custom_mesh_material.basemat file from the data/materials folder by using plain text editor. Откройте файл custom_mesh_material.basemat из папки data/materials с помощью текстового редактора.
  2. Modify it as follows:
    Source Code (ULON)
    // describing the read-only custom mesh material to be used for static meshes, 
    // setting prefixes to be used in shaders to refer to textures and parameters 
    BaseMaterial custom_mesh_material <node=ObjectMeshStatic editable=false var_prefix=var texture_prefix=tex>
    {
    	// enabling the deferred pass for our material and hiding it (will be invisible in the UnigineEditor)
    	State deferred=1	<internal=true>
    	
    	// describing textures and parameters
    	Group "Base"
    	{
    		Texture2D albedo="core/textures/common/grain.dds" <unit=0 pass=[deferred] tooltip="Albedo texture">
    		Texture2D displacement="core/textures/common/white.dds" <unit=1 pass=[deferred] tooltip="Displacement map">
    		Slider displacement_scale=0 <min=-0.5 max=0.5 tooltip="Displacement scale">
    	}
    
    	//////////////////////////////////////////////////////////////////////////
    	// Passes
    	//////////////////////////////////////////////////////////////////////////
    
    	// describing the deferred pass with links to shaders to be used
    	Pass deferred <defines="BASE_DEFERRED">
    	{
    		Vertex   = "shaders/vertex/deferred.vert"
    		Fragment = "shaders/fragment/deferred.frag"
    	}
    	
    	// describing bindings for node types to which the material is to be applicable
    	Bind ObjectMeshStatic=ObjectMeshDynamic
    	Bind ObjectMeshStatic=ObjectMeshSkinned
    }
    Измените его следующим образом:
    Source Code (ULON)
    // describing the read-only custom mesh material to be used for static meshes, 
    // setting prefixes to be used in shaders to refer to textures and parameters 
    BaseMaterial custom_mesh_material <node=ObjectMeshStatic editable=false var_prefix=var texture_prefix=tex default=true>
    {
    	// enabling the deferred pass for our material and hiding it (will be invisible in the UnigineEditor)
    	State deferred=1	<internal=true>
    	
    	// describing textures and parameters
    	Group "Base"
    	{
    		Texture2D albedo="core/textures/common/grain.dds" <unit=0 pass=[deferred] tooltip="Albedo texture">
    		Texture2D displacement="core/textures/common/white.dds" <unit=1 pass=[deferred] tooltip="Displacement map">
    		Slider displacement_scale=0 <min=-0.5 max=0.5 tooltip="Displacement scale">
    	}
    
    	//////////////////////////////////////////////////////////////////////////
    	// Passes
    	//////////////////////////////////////////////////////////////////////////
    
    	// describing the deferred pass with links to shaders to be used
    	Pass deferred <defines="BASE_DEFERRED">
    	{
    		Vertex   = "shaders/vertex/deferred.vert"
    		Fragment = "shaders/fragment/deferred.frag"
    	}
    	
    	// describing bindings for node types to which the material is to be applicable
    	Bind ObjectMeshStatic=ObjectMeshDynamic
    	Bind ObjectMeshStatic=ObjectMeshSkinned
    }

Now the textures and the parameter will be available for the shaders. We specified the name of the texture, rendering pass, and the path to the default texture. Our parameter (displacement_scale) shall be controlled by a slider with the specified minimum, maximum, and default values. Теперь текстуры и параметр будут доступны для шейдеров. Мы указали имя текстуры, проход рендеринга и путь к текстуре по умолчанию. Наш параметр (displacement_scale) должен управляться ползунком с указанными минимальным, максимальным и значениями по умолчанию.

Editing the Vertex ShaderРедактирование вершинного шейдера#

Now we should edit the vertex shader code and add the texture to the shader. Теперь нам нужно отредактировать код вершинного шейдера и добавить текстуру в шейдер.

The best way to add the texture in the shader (an example): Лучший способ добавить текстуру в шейдер (пример):

USL
// Initialize the texture slot for a texture named TEX_COLOR
INIT_TEXTURE(0, TEX_COLOR)

It makes changing the number of textures slots easy without correction of the whole shader's code. Let's do it in the vertex shader: Позволяет легко изменить количество слотов текстур без корректировки всего кода шейдера. Сделаем это в вершинном шейдере:

  1. Open the vertex shader deferred.vert file in the data/shaders/vertex folder by using plain text editor. Откройте файл вершинного шейдера deferred.vert в папке data/shaders/vertex с помощью текстового редактора.
  2. Edit the source code in the following way:
    Source code (UUSL)
    // Include Unified Unigine Shader Language (UUSL) header
    #include <core/shaders/common/common.h>
    
    // Input data struct
    STRUCT(VERTEX_IN)
    	INIT_ATTRIBUTE(float4,0,POSITION)	// Vertex position
    	INIT_ATTRIBUTE(float4,1,TEXCOORD0)	// Vertex texcoord (uv)
    	INIT_ATTRIBUTE(float4,2,TEXCOORD1)	// Vertex basis tangent
    	INIT_ATTRIBUTE(float4,3,TEXCOORD2)	// Vertex color
    	INIT_INSTANCE
    END
    
    // Our output vertex data struct
    STRUCT(VERTEX_OUT)
    	INIT_POSITION						// Out projected position
    	INIT_OUT(float4,0)					// Texcoord (uv)
    	INIT_OUT(float3,1)					// Vertex TBN (X)
    	INIT_OUT(float3,2)					// Vertex TBN (Y)
    	INIT_OUT(float3,3)					// Vertex TBN (Z)
    END
    
    MAIN_BEGIN(VERTEX_OUT,VERTEX_IN)
    	
    	// Get transform with scale and rotation (without translation)
    	float4x4 transform = getObjectTransform(IN_INSTANCE);
    	float4 row_0 = transform[0];
    	float4 row_1 = transform[1];
    	float4 row_2 = transform[2];
    	
    	// Perform Modelview-space transform
    	float4 in_vertex = float4(IN_ATTRIBUTE(0).xyz,1.0f);
    	float4 position = mul4(row_0,row_1,row_2,in_vertex);
    	
    	// Set output UV
    	float4 texcoord = IN_ATTRIBUTE(1);
    	OUT_DATA(0) = texcoord;
    	
    	// Define tangent basis
    	float3 tangent,binormal,normal;
    	
    	// Get normal in object-space
    	getTangentBasis(IN_ATTRIBUTE(2),tangent,binormal,normal);
    	
    	// Transform object-space TBN into camera-space TBN
    	normal = normalize(mul3(row_0,row_1,row_2,normal));
    	tangent = normalize(mul3(row_0,row_1,row_2,tangent));
    	binormal = normalize(mul3(row_0,row_1,row_2,binormal));
    	
    	// Set output TBN matrix
    	OUT_DATA(1) = float3(tangent.x,binormal.x,normal.x);
    	OUT_DATA(2) = float3(tangent.y,binormal.y,normal.y);
    	OUT_DATA(3) = float3(tangent.z,binormal.z,normal.z);
    	
    	// Set the texture
    	float4 displacement = TEXTURE_BIAS_ZERO(tex_displacement,texcoord.xy);
    	
    	// Perform the displacement mapping using the Displacement Scale parameter of the material (with the "var" prefix")
    	position.rgb += normal * (displacement.r * var_displacement_scale);
    	
    	// Set output position
    	OUT_POSITION = getPosition(position);
    
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).You should add a new line (press Enter) after closing the instruction (after MAIN_END command).
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).
    Отредактируйте исходный код следующим образом:
    Source code (UUSL)
    // Include Unified Unigine Shader Language (UUSL) header
    #include <core/shaders/common/common.h>
    
    // Create a texture sampler (slot 0 is used in the fragment shader for the color texture)
    INIT_TEXTURE(1,TEX_HEIGHT)
    
    // Input data struct
    STRUCT(VERTEX_IN)
    	INIT_ATTRIBUTE(float4,0,POSITION)	// Vertex position
    	INIT_ATTRIBUTE(float4,1,TEXCOORD0)	// Vertex texcoord (uv)
    	INIT_ATTRIBUTE(float4,2,TEXCOORD1)	// Vertex basis tangent
    	INIT_ATTRIBUTE(float4,3,TEXCOORD2)	// Vertex color
    	INIT_INSTANCE
    END
    
    // Our output vertex data struct
    STRUCT(VERTEX_OUT)
    	INIT_POSITION						// Out projected position
    	INIT_OUT(float4,0)					// Texcoord (uv)
    	INIT_OUT(float3,1)					// Vertex TBN (X)
    	INIT_OUT(float3,2)					// Vertex TBN (Y)
    	INIT_OUT(float3,3)					// Vertex TBN (Z)
    END
    
    MAIN_BEGIN(VERTEX_OUT,VERTEX_IN)
    	
    	// Get transform with scale and rotation (without translation)
    	float4x4 transform = getObjectTransform(IN_INSTANCE);
    	float4 row_0 = transform[0];
    	float4 row_1 = transform[1];
    	float4 row_2 = transform[2];
    	
    	// Perform Modelview-space transform
    	float4 in_vertex = float4(IN_ATTRIBUTE(0).xyz,1.0f);
    	float4 position = mul4(row_0,row_1,row_2,in_vertex);
    	
    	// Set output UV
    	float4 texcoord = IN_ATTRIBUTE(1);
    	OUT_DATA(0) = texcoord;
    	
    	// Define tangent basis
    	float3 tangent,binormal,normal;
    	
    	// Get normal in object-space
    	getTangentBasis(IN_ATTRIBUTE(2),tangent,binormal,normal);
    	
    	// Transform object-space TBN into camera-space TBN
    	normal = normalize(mul3(row_0,row_1,row_2,normal));
    	tangent = normalize(mul3(row_0,row_1,row_2,tangent));
    	binormal = normalize(mul3(row_0,row_1,row_2,binormal));
    	
    	// Set output TBN matrix
    	OUT_DATA(1) = float3(tangent.x,binormal.x,normal.x);
    	OUT_DATA(2) = float3(tangent.y,binormal.y,normal.y);
    	OUT_DATA(3) = float3(tangent.z,binormal.z,normal.z);
    	
    	// Set the texture
    	float4 displacement = TEXTURE_BIAS_ZERO(TEX_HEIGHT,texcoord.xy);
    	
    	// Perform the displacement mapping using the Displacement Scale parameter of the material (with the "var" prefix")
    	position.rgb += normal * (displacement.r * var_displacement_scale);
    	
    	// Set output position
    	OUT_POSITION = getPosition(position);
    
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command). Вам следует добавить новую строку (нажмите Enter) после закрытия инструкции (после командыMAIN_END).
  3. Save the file. Сохраните файл.

That's it! Our vertex shader now calculates normals, gets a texture and performs displacement mapping taking into account the scale value. We've added three new output semantics and now we should receive them in our fragment shader. Вот и все! Наш вершинный шейдер теперь вычисляет нормали, получает текстуру и выполняет отображение смещения с учетом значения масштаба. Мы добавили три новых семантики вывода, и теперь мы должны получать их в нашем шейдере фрагментов.

Примечание
Note that your changes are not applied automatically (hot reload is disabled for shaders and materials). While in Editor, press F7 to reload materials. Обратите внимание, что ваши изменения не применяются автоматически (горячая перезагрузка отключена для шейдеров и материалов). В редакторе нажмите F7, чтобы перезагрузить материалы.

Editing the Fragment ShaderРедактирование фрагментного шейдера#

Now we should edit the fragment shader code and add the albedo texture to the shader. Теперь нам нужно отредактировать код фрагментного шейдера и добавить в шейдер текстуру альбедо.

  1. Open the fragment shader deferred.frag file in the data/shaders/fragment folder by using plain text editor. Откройте файл фрагментного шейдера deferred.frag в папке data/shaders/fragment с помощью текстового редактора.
  2. Edit the source code in the following way:
    Исходный код
    // Include the UUSL language header
    #include <core/shaders/common/fragment.h>
    
    STRUCT(FRAGMENT_IN)
    	INIT_POSITION				// Projected position
    	INIT_IN(float4,0)			// Texcoord (uv)
    	INIT_IN(float3,1)			// Vertex TBN (X)
    	INIT_IN(float3,2)			// Vertex TBN (Y)
    	INIT_IN(float3,3)			// Vertex TBN (Z)
    END
    
    MAIN_BEGIN_DEFERRED(FRAGMENT_IN)
    	
    	// Get the UV coords
    	float4 texcoord = IN_DATA(0);
    
    	// Get the texture data
    	float4 texture_data = TEXTURE(tex_albedo,texcoord.xy);
    	
    	// Define the normal of a fragment in tangent-space
    	STATICVAR float3 tangentspace_normal = float3(0.0f,0.0f,1.0f);
    	
    	// Calculate the view-space normal
    	float3 viewspace_normal;
    	viewspace_normal.x = dot(IN_DATA(1),tangentspace_normal);
    	viewspace_normal.y = dot(IN_DATA(2),tangentspace_normal);
    	viewspace_normal.z = dot(IN_DATA(3),tangentspace_normal);
    	viewspace_normal = normalize(viewspace_normal);
    
    	// Fill G-Buffer: set the calculated normal and albedo color of the texture
    	GBuffer gbuffer = GBufferDefault();
    	gbuffer.albedo = texture_data.rgb;
    	gbuffer.normal = viewspace_normal;
    
    	setGBuffer(gbuffer);
    	
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).You should add a new line (press Enter) after closing the instruction (after MAIN_END command).
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command).
    Отредактируйте исходный код следующим образом:
    Исходный код
    // Include the UUSL language header
    #include <core/shaders/common/fragment.h>
    
    // Adds a texture sampler  (slot 0)
    INIT_TEXTURE(0, TEX_COLOR)
    
    STRUCT(FRAGMENT_IN)
    	INIT_POSITION				// Projected position
    	INIT_IN(float4,0)			// Texcoord (uv)
    	INIT_IN(float3,1)			// Vertex TBN (X)
    	INIT_IN(float3,2)			// Vertex TBN (Y)
    	INIT_IN(float3,3)			// Vertex TBN (Z)
    END
    
    MAIN_BEGIN_DEFERRED(FRAGMENT_IN)
    	
    	// Get the UV coords
    	float4 texcoord = IN_DATA(0);
    
    	// Get the texture data
    	float4 texture_data = TEXTURE(TEX_COLOR,texcoord.xy);
    	
    	// Define the normal of a fragment in tangent-space
    	STATICVAR float3 tangentspace_normal = float3(0.0f,0.0f,1.0f);
    	
    	// Calculate the view-space normal
    	float3 viewspace_normal;
    	viewspace_normal.x = dot(IN_DATA(1),tangentspace_normal);
    	viewspace_normal.y = dot(IN_DATA(2),tangentspace_normal);
    	viewspace_normal.z = dot(IN_DATA(3),tangentspace_normal);
    	viewspace_normal = normalize(viewspace_normal);
    
    	// Fill G-Buffer: set the calculated normal and albedo color of the texture
    	GBuffer gbuffer = GBufferDefault();
    	gbuffer.albedo = texture_data.rgb;
    	gbuffer.normal = viewspace_normal;
    
    	setGBuffer(gbuffer);
    	
    MAIN_END
    
    // end
    Внимание
    You should add a new line (press Enter) after closing the instruction (after MAIN_END command). Вам следует добавить новую строку (нажмите Enter) после закрытия инструкции (после командыMAIN_END).
  3. Save the file. Сохраните файл.

Now our shaders are ready to work! Let's see them in action! Теперь наши шейдеры готовы к работе! Давайте посмотрим на них в действии!

Editing the MaterialРедактирование материала#

We've changed our materials and shaders, so we should reload them by using the relative console commands. Мы изменили наши материалы и шейдеры, поэтому мы должны перезагрузить их, используя соответствующие консольные команды.

Open the console and execute the materials_reload command (or use the corresponding hotkey). Откройте консоль и выполните команду materials_reload (или используйте соответствующую горячую клавишу ).

Now the result is different — we see the white lit sphere: Теперь результат другой - мы видим светящуюся белую сферу:

It looks much better! But let's go a bit further. Perform the following actions: Выглядит намного лучше! Но пойдем немного дальше. Выполните следующие действия:

  1. Inherit a material from your custom base material (a child material named custom_mesh_material_0 will be created).
    Наследуйте материал из вашего настраиваемого основного материала (будет создан дочерний материал с именем custom_mesh_material_0).
  2. Assign the created child material custom_mesh_material_0 to the sphere by dragging it to the object. Назначьте созданный дочерний материал custom_mesh_material_0 сфере, перетащив его на объект.
  3. Go to the Parameters window.
    Перейдите в окно Parameters.
  4. Choose the Albedo and the Displacement textures for the material and adjust the Displacement Scale parameter.
    Примечание
    You can also switch the parameter to the Expression mode and insert a script to animate the value, e.g.: sin(time)/2You can also switch the parameter to the Expression mode and insert a script to animate the value, e.g.: sin(time)/2
    You can also switch the parameter to the Expression mode and insert a script to animate the value, e.g.: sin(time)/2
    Выберите текстуры Albedo и Displacement для материала и настройте параметр Displacement Scale.
    Примечание
    You can also switch the parameter to the Expression mode and insert a script to animate the value, e.g.: sin(time)/2 Вы также можете переключить параметр в режим Expression и вставить скрипт для анимации значения, например: sin (time) / 2

Voila! We just created a new deferred material with own shaders which uses two textures for albedo and displacement mapping! Вуаля! Мы только что создали новый отложенный материал с собственными шейдерами, который использует две текстуры для отображения альбедо и смещения!

Последнее обновление: 11.11.2020