可编写脚本的材质
A scriptable material is a base material with expressions (fragments of code written in UnigineScript) executed at certain stages of rendering sequence offering you an exceptional flexibility. For example, you can use them to create your own custom post effects such as DoF or Bloom.可编写脚本的材质是具有表达式(用 UnigineScript 编写的代码片段)的基础材质 渲染顺序为您提供了极大的灵活性。例如,您可以使用它们来创建自己的自定义后期效果,例如DoF或Bloom。
Scriptable materials represent an ideal instrument for fast prototyping of any custom effects, as they allow you to:可编写脚本的材质代表了快速定制任何特效的理想工具,因为它们使您能够:
- write any logic in UnigineScript,用UnigineScript编写任何逻辑,
- apply them globally or per-camera,全局或按摄像机应用它们,
- have all necessary parameters added to UI automatically.将所有必需的参数自动添加到UI。
A single or multiple scriptable materials can be applied globally via the corresponding tab of the Settings window (usually, the Custom Post Materials tab) or attached to a certain camera via the Parameters window. Expressions assigned to a scriptable material are executed only if the material is enabled. The order of execution is defined by the material's number in the list of appllied scriptable materials (either global or camera-specific). The order can be changed if necessary.可以全局(通过Settings窗口的Scriptable Materials部分)应用单个或多个可编写脚本的材质,也可以将其附加到某个摄像机(通过Settings窗口)。仅在启用材质的情况下才执行分配给可脚本化材质的表达式。执行顺序由适用的可编写脚本的材质列表(全局或特定于摄像机)中的材质编号定义。必要时可以更改顺序。
Scriptable material lists are pretty much like the lists of components assigned to nodes, enabling you to adjust all available parameters and control which materials to apply.可编写脚本的材质列表与分配给节点的组件列表非常相似,使您可以调整所有可用参数并控制要应用的材质。
As base materials, scriptable ones are created and edited manually.作为基础材质,可手动编写和编辑可编写脚本的材质。
Creating a Scriptable Base Material with ULON使用ULON创建可编写脚本的基础材质#
The custom scriptable base material is the same as the default one: it is read-only, non-hierarchical, referred by the name and so on.可自定义脚本化的基础材质与默认材质相同:它是只读的,非分层的,由名称和引用引用。
Let's write a material in the ULON file format.让我们以 ULON文件格式编写材质。
Implementing Material Logic实施材质逻辑#
- Create the post_sobel.basemat text file in the data/materials folder and open it in a plain text editor.在data/materials文件夹中创建post_sobel.basemat文本文件,然后在纯文本编辑器中将其打开。
- Specify the name for the base material and attributes for it.
指定基础材质的名称和属性。
BaseMaterial post_sobel <preview_hidden=1 var_prefix=var texture_prefix=tex> { ... }
BaseMaterial post_sobel <options_hidden=1 preview_hidden=1 var_prefix=var texture_prefix=tex> { ... }
- Describe material's resources and parameters.
描述材质的资源和参数。
// specify an internal texture to be used Texture src_color <source=procedural internal=true> // define the material's states and parameters available in the Editor Group "Sobel operator" { State multiply = false Slider threshold = 1.0 <min=0.0 max=1.0> Slider scale = 1.0 <min=0.0 max=1.0> }
// specify an internal texture to be used Texture src_color <type=procedural internal=true> // define the material's states and parameters available in the Editor Group "Sobel operator" { State multiply = false Slider threshold = 1.0 <min=0.0 max=1.0> Slider scale = 1.0 <min=0.0 max=1.0> }
- Write the fragment shader for the custom outline render pass.
为自定义轮廓渲染过程编写片段着色器。
// define the outline render pass Pass render_sobel_operator { // write the fragment shader in UUSL or HLSL/GLSL Fragment= #{ #include <core/materials/shaders/render/common.h> STRUCT_FRAG_BEGIN INIT_COLOR(float4) STRUCT_FRAG_END MAIN_FRAG_BEGIN(FRAGMENT_IN) // get the inverse resolution of the viewport (1.0 / width, 1.0 / height) float2 offset = s_viewport.zw; // take 3x3 samples OUT_COLOR = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV); float3 c0 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 0)).rgb; float3 c1 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, 1)).rgb; float3 c2 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 1)).rgb; float3 c3 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, -1)).rgb; float3 c4 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 0)).rgb; float3 c5 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, -1)).rgb; float3 c6 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, -1)).rgb; float3 c7 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 1)).rgb; // find edge with Sobel filter float3 sobel_x = c6 + c4 * 2.0f + c7 - c3 - c0 * 2.0f - c2; float3 sobel_y = c6 + c5 * 2.0f + c3 - c7 - c1 * 2.0f - c2; float3 sobel = sqrt(sobel_x * sobel_x + sobel_y * sobel_y); // apply threshold float edge = saturate(1.0f - dot(sobel, toFloat3(var_threshold))); // apply scale float3 result = saturate(OUT_COLOR.rgb + var_scale) * edge; #ifdef STATE_MULTIPLY OUT_COLOR.rgb *= result; // for colored result #else OUT_COLOR.rgb = result; // for black & white result #endif MAIN_FRAG_END #} }
// define the outline render pass Pass render_sobel_operator { // write the fragment shader in UUSL or HLSL/GLSL Fragment= #{ #include <core/shaders/common/fragment.h> MAIN_BEGIN(FRAGMENT_OUT, FRAGMENT_IN) // get the inverse resolution of the viewport (1.0 / width, 1.0 / height) float2 offset = s_viewport.zw; // take 3x3 samples OUT_COLOR = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV); float3 c0 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 0)).rgb; float3 c1 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, 1)).rgb; float3 c2 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 1)).rgb; float3 c3 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, -1)).rgb; float3 c4 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 0)).rgb; float3 c5 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, -1)).rgb; float3 c6 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, -1)).rgb; float3 c7 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 1)).rgb; // find edge with Sobel filter float3 sobel_x = c6 + c4 * 2.0f + c7 - c3 - c0 * 2.0f - c2; float3 sobel_y = c6 + c5 * 2.0f + c3 - c7 - c1 * 2.0f - c2; float3 sobel = sqrt(sobel_x * sobel_x + sobel_y * sobel_y); // apply threshold float edge = saturate(1.0f - dot(sobel, to_float3(var_threshold))); // apply scale float3 result = saturate(OUT_COLOR.rgb + var_scale) * edge; #ifdef STATE_MULTIPLY OUT_COLOR.rgb *= result; // for colored result #else OUT_COLOR.rgb = result; // for black & white result #endif MAIN_END #} }
- Write the Expression callback in Unigine Script to be called after the Post Materials stage (EndPostMaterials event) of the render sequence to perform outline render pass with Sobel filter.
在Unigine脚本中编写Expression回调,以便在Post Materials阶段(EndPostMaterials 事件)渲染序列,以使用Sobel滤镜执行轮廓渲染。
// the expression in Unigine Script defines a callback Expression RENDER_CALLBACK_END_POST_MATERIALS = #{ // declare the source texture from the screen frame Texture source = engine.render.getTemporaryTexture(engine.render_state.getScreenColorTexture()); // define the source texture from the screen frame source.copy(engine.render_state.getScreenColorTexture()); //set the color source texture to use it in the shader setTexture("src_color", source); // render the outline result texture to output it to the screen renderPassToTexture("render_sobel_operator", engine.render_state.getScreenColorTexture()); // release the temporaty texture engine.render.releaseTemporaryTexture(source); #}
// the expression in Unigine Script defines a callback Expression RENDER_CALLBACK_END_POST_MATERIALS = #{ // declare the source texture from the screen frame Texture source = engine.render.getTemporaryTexture(engine.render_state.getScreenColorTexture()); // define the source texture from the screen frame source.copy(engine.render_state.getScreenColorTexture()); //set the color source texture to use it in the shader setTexture("src_color", source); // render the outline result texture to output it to the screen renderPassToTexture("render_sobel_operator", engine.render_state.getScreenColorTexture()); // release the temporaty texture engine.render.releaseTemporaryTexture(source); #}
- The full source code for the material is given below. You can copy it to the post_sobel.basemat and save the file.
该材质的完整源代码如下。 您可以将其复制到post_sobel.basemat并保存文件。
BaseMaterial post_sobel <preview_hidden=1 var_prefix=var texture_prefix=tex> { // specify an internal texture to be used Texture src_color <source=procedural internal=true> // define the material's states and parameters available in the Editor Group "Sobel operator" { State multiply = false Slider threshold = 1.0 <min=0.0 max=1.0> Slider scale = 1.0 <min=0.0 max=1.0> } // define the outline render pass Pass render_sobel_operator { // write the fragment shader in UUSL or HLSL/GLSL Fragment= #{ #include <core/materials/shaders/render/common.h> STRUCT_FRAG_BEGIN INIT_COLOR(float4) STRUCT_FRAG_END MAIN_FRAG_BEGIN(FRAGMENT_IN) // get the inverse resolution of the viewport (1.0 / width, 1.0 / height) float2 offset = s_viewport.zw; // take 3x3 samples OUT_COLOR = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV); float3 c0 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 0)).rgb; float3 c1 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, 1)).rgb; float3 c2 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 1)).rgb; float3 c3 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, -1)).rgb; float3 c4 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 0)).rgb; float3 c5 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, -1)).rgb; float3 c6 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, -1)).rgb; float3 c7 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 1)).rgb; // find edge with Sobel filter float3 sobel_x = c6 + c4 * 2.0f + c7 - c3 - c0 * 2.0f - c2; float3 sobel_y = c6 + c5 * 2.0f + c3 - c7 - c1 * 2.0f - c2; float3 sobel = sqrt(sobel_x * sobel_x + sobel_y * sobel_y); // apply threshold float edge = saturate(1.0f - dot(sobel, toFloat3(var_threshold))); // apply scale float3 result = saturate(OUT_COLOR.rgb + var_scale) * edge; #ifdef STATE_MULTIPLY OUT_COLOR.rgb *= result; // for colored result #else OUT_COLOR.rgb = result; // for black & white result #endif MAIN_FRAG_END #} } // the expression in Unigine Script defines a callback Expression RENDER_CALLBACK_END_POST_MATERIALS = #{ // declare the source texture from the screen frame Texture source = engine.render.getTemporaryTexture(engine.render_state.getScreenColorTexture()); // define the source texture from the screen frame source.copy(engine.render_state.getScreenColorTexture()); //set the color source texture to use it in the shader setTexture("src_color", source); // render the outline result texture to output it to the screen renderPassToTexture("render_sobel_operator", engine.render_state.getScreenColorTexture()); // release the temporaty texture engine.render.releaseTemporaryTexture(source); #} }
BaseMaterial post_sobel <options_hidden=1 preview_hidden=1 var_prefix=var texture_prefix=tex> { // specify an internal texture to be used Texture src_color <type=procedural internal=true> // define the material's states and parameters available in the Editor Group "Sobel operator" { State multiply = false Slider threshold = 1.0 <min=0.0 max=1.0> Slider scale = 1.0 <min=0.0 max=1.0> } // define the outline render pass Pass render_sobel_operator { // write the fragment shader in UUSL or HLSL/GLSL Fragment= #{ #include <core/shaders/common/fragment.h> MAIN_BEGIN(FRAGMENT_OUT, FRAGMENT_IN) // get the inverse resolution of the viewport (1.0 / width, 1.0 / height) float2 offset = s_viewport.zw; // take 3x3 samples OUT_COLOR = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV); float3 c0 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 0)).rgb; float3 c1 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, 1)).rgb; float3 c2 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, 1)).rgb; float3 c3 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 1, -1)).rgb; float3 c4 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 0)).rgb; float3 c5 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2( 0, -1)).rgb; float3 c6 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, -1)).rgb; float3 c7 = TEXTURE_BIAS_ZERO(tex_src_color, IN_UV + offset * float2(-1, 1)).rgb; // find edge with Sobel filter float3 sobel_x = c6 + c4 * 2.0f + c7 - c3 - c0 * 2.0f - c2; float3 sobel_y = c6 + c5 * 2.0f + c3 - c7 - c1 * 2.0f - c2; float3 sobel = sqrt(sobel_x * sobel_x + sobel_y * sobel_y); // apply threshold float edge = saturate(1.0f - dot(sobel, to_float3(var_threshold))); // apply scale float3 result = saturate(OUT_COLOR.rgb + var_scale) * edge; #ifdef STATE_MULTIPLY OUT_COLOR.rgb *= result; // for colored result #else OUT_COLOR.rgb = result; // for black & white result #endif MAIN_END #} } // the expression in Unigine Script defines a callback Expression RENDER_CALLBACK_END_POST_MATERIALS = #{ // declare the source texture from the screen frame Texture source = engine.render.getTemporaryTexture(engine.render_state.getScreenColorTexture()); // define the source texture from the screen frame source.copy(engine.render_state.getScreenColorTexture()); //set the color source texture to use it in the shader setTexture("src_color", source); // render the outline result texture to output it to the screen renderPassToTexture("render_sobel_operator", engine.render_state.getScreenColorTexture()); // release the temporaty texture engine.render.releaseTemporaryTexture(source); #} }
Applying Material and Adjusting Parameters施加材质和调整参数#
- Launch the UNIGINE Editor via the SDK Browser. In the Materials tab, you will find the imported post_sobel material in the list of base materials.
通过SDK浏览器启动UnigineEditor。在``材质''选项卡中,您可以在基础材质列表中找到导入的post_sobel材质。
- To apply the material globally, go to Windows -> Settings and in the Custom Post Materials section click Add New Material. Assign the post_sobel material by dragging it to the field or by specifying the name of the material. 要全局应用材质,请转到Windows -> Settings,然后在Scriptable Materials部分中单击Add New Scriptable Material。通过将post_sobel材质拖到字段或指定材质名称来分配它。
- Click create a child material to be able to specify states and parameters of the material. The new child material of the post_sobel will be created and assigned here.
单击create a child material可以指定材质的状态和参数。 post_sobel的新子材质将在此处创建和分配。
- Check Multiply to make a colorful final image. Adjust the Threshold and Scale values to customize the effect.
The applied post process outline effect.The applied post process outline effect.The applied post process outline effect.选中Multiply以制作彩色的最终图像。调整Threshold和Scale值以自定义效果。The applied post process outline effect.应用的后期处理轮廓效果。
That's it! You have just created a scriptable material for all of the application’s cameras. To apply the post process effect only to a specific camera, go to the Parameters tab of the corresponding Player node and assign the material to it.
就是这样!您刚刚为应用程序的所有摄像机创建了可编写脚本的材质。要将后期处理效果仅应用于特定相机,请转到相应Player节点的Parameters选项卡并为其分配材质。