# Custom Shader

In the small game framework, the custom Shader is written in HLSL-like syntax, and the provided tool chain will cross-platform HLSL into GLSL/MSL/SPIR-V to run in different environments

# Shader input

# Use header files

The Shader can introduce header files in the following two ways

#include<common.inc>
#include "something.hlsl"

The header file that is introduced by <> is the built-in header file of the mini game framework, and the header file customized by the developer can be imported by "", and the file relative path is used for indexing.

# Define and use textures

The use of shaders in the game framework can declare and sample textures through macros

// Declaration and sampling of normal texture
DECLARE_TEXTURE(_MainTex);
float4 color = SAMPLE_TEXTURE(name, TexCoord);

// Cube Map declaration and sampling
DECLARE_CUBEMAP(SpeCube);
SAMPLE_CUBEMAP(SpeCube, reflectVec);

When setting texture by material, you need to declare the texture used in .effect. For details, please refer to Effect and Material

# Define Shader Variables

At present, the small game framework supports players to define Shader variables in a Constant Buffer for material use, which can be named cbuffer Material. Can refer to the following definition

cbuffer Material
{
    float4 _MainTex_ST;
    float4 _Color;
}

Due to efficiency and compatibility issues, the definition of cbuffer used in the vertex shader and pixel shader must be consistent, and unused uniforms will be eliminated in the optimization process.

The built-in Shader Variables in the mini game framework include the following

WorldSpaceViewPosition: float3 camera position
WorldSpaceLightDir: float3 parallel light direction
LightColor: float3 light color
AmbientLight: float3 ambient light color, used for multiple light sources
GameTime: float current game time
ShadowStrength: float shadow strength
ShadowColor: float3 shadow color
EnvironmentMap: Cubemap environment map

# Define vertex input and output

In the small game framework, the vertex input is determined. Feffect3DVertexInput is a built-in vertex structure, which is referenced to the shader through the common.inc file. The developer needs to define the output of the vertex shader in the vertex shader.

#include <common.inc>

struct FVertexOutput
{
    float4 Position: SV_Position;
    float2 TexCoord: TEXCOORD0; // world space light direction
    float3 LightDir: TEXCOORD1; // world space view direction
    float3 ViewDir: TEXCOORD2; // world space normal direction
    float3 WorldNormal:TEXCOORD3;
    LIGHTMAP_COORDS(4) //builtin lightmap coords
    FOG_COORDS(5) // builtin fog cooord
    SHADOW_COORDS(6) // builtin shadow coord
};

The vertex output content will be passed to the pixel shader as varing in GLES2.0

# Write a set of shaders

Combining the above content, let's look at a set of simple Shader implementations

// simple3D.vertex.hlsl

// Public header files, including built-in hlsl functions, macros and structure definitions
#include <common.inc>

// Material definition, need to be consistent with the configuration in the .effect file
cbuffer material
{
    float4 _MainTex_ST;
    float4 _Color;
}
// vertex output, the data passed from vertex to fragment
struct FVertexOutput
{
    float4 Position: SV_Position;
    float2 TexCoord: TEXCOORD0;
};

// vertex entry function
void Main(in FEffect3DVertexInput In, out FVertexOutput Out)
{
    // Built-in vertex processing, particle/Skin/Line/Trail and other vertex processing
FVertexProcessOutput VPOut;
Effect3DVertexProcess(In, VPOut);

    Out.Position = WorldToClipPosition(VPOut.WorldPosition);
    Out.TexCoord = TRANSFER_TEXCOORD(VPOut.TexCoord, _MainTex_ST);
}
// simple3D.pixel.hlsl

#include <common.inc>
cbuffer material
{
    float4 _MainTex_ST;
    float4 _Color;
}
struct FVertexOutput
{
    float4 Position: SV_Position;
    float2 TexCoord: TEXCOORD0;
};

// The texture declaration must be consistent with the declaration in the .effect file
DECLARE_TEXTURE(_MainTex);
float4 Main(in FVertexOutput In): SV_Target0
{
    fixed4 texColor = SAMPLE_TEXTURE(_MainTex, In.TexCoord);
    return texColor * _Color;
}

# Built-in functions

  • General built-in functions
// Transform
// Convert local space position to world Space
float3 ObjectToWorldNormal(float3 normal);
// Convert world space position to clip space
float4 ObjectToWorldPosition(float4 point);
// Calculate the UV coordinates and scaleOffset, and output the final UV coordinates
float2 TRANSFER_TEXCOORD(float2 TexCoord, float4 ScaleOffset);
  • Built-in functions used in the vertex shader
//Built-in vertex processing, particle/Skin/Line/Trail and other vertex processing
void Effect3DVertexProcess(in FEffect3DVertexInput In, out FVertexProcessOutput Out);
// Calculation of shadow parameters in the vertex shader
void TRANSFER_SHADOW(FVertexProcessOutput Out, float3 WorldPos);
// Calculation of fog effect parameters in vertex shader
void TRANSFER_FOG(FVertexProcessOutput Out, float3 WorldPos);
// Light Map parameter calculation in vertex shader
void TRANSFER_LIGHTMAP(in FEffect3DVertexInput In, out FVertexProcessOutput Out);

// When Instancing is turned on, you can use the following built-in functions to transform in the vertex shader
float3 ObjectToWorldDirInstancing(in FEffect3DVertexInput In, float3 dir);
float3 ObjectToWorldNormalInstancing(in FEffect3DVertexInput In, float3 normal);
float4 ObjectToWorldPositionInstancing(in FEffect3DVertexInput In, float4 point1);
  • Built-in functions used in the pixel shader
// Calculate the shadow
float SHADOW_ATTENUATION(FVertexOutput In);
// Lightmap sampling
float3 SAMPLE_LIGHTMAP(FVertexOutput In);
// Calculate the fog effect value
APPLY_FOG(FVertexOutput In, out float4 Color);

# Grammar Rules

  • Matrix storage and access sequence In the runtime of the mini game framework, the matrix is ​​stored by default in a column matrix. Similarly, in the Shader, the matrix uses a column matrix by default, and the access to the matrix uses the same column-major order access as the runtime, that is, matrix. The way of [col][row]. The multiplication rule adopts the same rule as CG/GLSL, namely mul(Matrix, Vector). For example, to perform MVP matrix transformation, the following methods can be used
mul(u_projection, mul(u_view, mul(u_world, position)));
  • Validity check The Shader tool written by the developer will perform HLSL grammar verification. For illegal grammar, the tool will prompt the wrong shader and line number in the tool. If the common structure defined by the developer in the vertex shader and pixel shader, such as FVertexOutput and cbuffer, is inconsistent, it may cause a Link error.

# Performance

The Shader compilation tool provided by the small game framework will make a certain degree of compilation optimization for the Shader written by the developer, including but not limited to

  • Function inlining
  • Loop unrolling
点击咨询小助手