Создание пользовательского шейдера для отложенного прохода рендеринга
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. В этой статье мы создаем материал для статических, динамических и скелетных мешей. Мы определяем карту высот для вершинного шейдера и текстуру альбедо для фрагментного шейдера. Кроме того, мы вычисляем нормали, чтобы обеспечить правильное освещение для нашей сетки.
- Getting StartedGetting Started
- Materials Files FormatsMaterials Files Formats
- Unigine Language Object Notation (ULON)Unigine Language Object Notation (ULON)
- UUSL Data Types and Common Intrinsic FunctionsUUSL Data Types and Common Intrinsic Functions
- UUSL TexturesUUSL Textures
- UUSL SemanticsUUSL Semantics
- UUSL ParametersUUSL Parameters
- Getting Started Начало работы
- Materials Files Formats Форматы файлов материалов
- Unigine Language Object Notation (ULON) Нотация объектов Unigine Language (ULON)
- UUSL Data Types and Common Intrinsic Functions Типы данных UUSL и общие внутренние функции
- UUSL Textures Текстуры UUSL
- UUSL Semantics Семантика UUSL
- UUSL Parameters Параметры UUSL
See AlsoСмотрите также#
- The article on Material Settings Статья о настройках материалов
- The article on Custom Materials Статья о Пользовательских материалах
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:
- In your project folder open the data/materials folder. В папке проекта откройте папку data/materials.
- Create a new custom_mesh_material.basemat file and implement the following base material:
// 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.
// 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. Наконец, мы определили привязки: типы сеток, для которых может быть назначен материал.
- 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: Нам понадобится создать два шейдера для нашего материала: вершинный и фрагментный. Чтобы создать вершинный шейдер, выполните следующие действия:
- Create the shaders folder in your project's /data folder. Создайте папку shaders в папке /data вашего проекта.
- Inside the shaders folder, create two folders: vertex for vertex shaders, fragment for fragment shaders. Внутри папки shaders создайте две папки: vertex для вершинных шейдеров, fragment для шейдеров фрагментов.
- Open a plain text editor and write the following:
// 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.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.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.
// 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. Установите выходной UV.
- Set the vertex position. Установите положение вершины.
- 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: Чтобы создать фрагментный шейдер, выполните следующие действия:
- Open a plain text editor and write the following:
// 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.
// 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 и устанавливаем его.
- 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: После выполнения всех этих шагов вы можете увидеть, что недавно созданные шейдеры используются. Они примитивны и не дают хорошего финального изображения. В любом случае, чтобы проверить их работу, выполните следующие действия:
- Open your world by using UnigineEditor, The Editor will create all necessary resources in the data folder. Откройте свой мир с помощью UnigineEditor. Редактор создаст все необходимые ресурсы в папке data.
- Open the Materials Hierarchy window. You will see the recently created base material in the hierarchy. Откройте окно Materials Hierarchy. Вы увидите недавно созданный базовый материал в иерархии.
- 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. Во-первых, давайте отредактируем наш собственный базовый материал и добавим два слота для текстур и параметр для управления смещением.
- Open the custom_mesh_material.basemat file from the data/materials folder by using plain text editor. Откройте файл custom_mesh_material.basemat из папки data/materials с помощью текстового редактора.
- Modify it as follows:
Измените его следующим образом:
// 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 }
// 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): Лучший способ добавить текстуру в шейдер (пример):
// 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: Позволяет легко изменить количество слотов текстур без корректировки всего кода шейдера. Сделаем это в вершинном шейдере:
- Open the vertex shader deferred.vert file in the data/shaders/vertex folder by using plain text editor. Откройте файл вершинного шейдера deferred.vert в папке data/shaders/vertex с помощью текстового редактора.
- Edit the source code in the following way:
// 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).// 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). - 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. Вот и все! Наш вершинный шейдер теперь вычисляет нормали, получает текстуру и выполняет отображение смещения с учетом значения масштаба. Мы добавили три новых семантики вывода, и теперь мы должны получать их в нашем шейдере фрагментов.
Editing the Fragment ShaderРедактирование фрагментного шейдера#
Now we should edit the fragment shader code and add the albedo texture to the shader. Теперь нам нужно отредактировать код фрагментного шейдера и добавить в шейдер текстуру альбедо.
- Open the fragment shader deferred.frag file in the data/shaders/fragment folder by using plain text editor. Откройте файл фрагментного шейдера deferred.frag в папке data/shaders/fragment с помощью текстового редактора.
- 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). - 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: Выглядит намного лучше! Но пойдем немного дальше. Выполните следующие действия:
- Inherit a material from your custom base material (a child material named custom_mesh_material_0 will be created).
Наследуйте материал из вашего настраиваемого основного материала (будет создан дочерний материал с именем custom_mesh_material_0).
- Assign the created child material custom_mesh_material_0 to the sphere by dragging it to the object. Назначьте созданный дочерний материал custom_mesh_material_0 сфере, перетащив его на объект.
- Go to the Parameters window.
Перейдите в окно Parameters.
- 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)/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)/2You 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 Вы также можете переключить параметр в режим Expression и вставить скрипт для анимации значения, например: sin (time) / 2
Voila! We just created a new deferred material with own shaders which uses two textures for albedo and displacement mapping! Вуаля! Мы только что создали новый отложенный материал с собственными шейдерами, который использует две текстуры для отображения альбедо и смещения!