Unlit Material
This article will take the built-in UnlitMaterial
as an example to illustrate how to create a material in the engine.
Creating a Material
Create a new Material
by inheriting from UnLitMaterial
。
export class UnLitMaterial extends Material {
constructor() {
super();
//...
}
}
Writing Shader Code
First, prepare the shader script to be edited. As an essential material, the unlit material often only needs to include
existing code segments.
//Import common vertex shader-related code
#include "Common_vert"
//Import common fragment shader-related code
#include "Common_frag"
//Import unlit material fragment shader code
#include "UnLit_frag"
//Import unlit material, uniform-related code
#include "UnLitMaterialUniform_frag"
Define the vertex shadervert
function:
fn vert(inputData:VertexAttributes) -> VertexOutput {
//Execute the built-in vertex shader function
ORI_Vert(inputData) ;
//Output vertex data
return ORI_VertexOut ;
}
Define the fragment shaderfrag
function:
fn frag(){
//Get the first UV offset data
var transformUV1 = materialUniform.transformUV1;
//Get the second UV offset data
var transformUV2 = materialUniform.transformUV2;
//Calculate real-time UV
var uv = transformUV1.zw * ORI_VertexVarying.fragUV0 + transformUV1.xy;
//Sample the baseMap as the output color
let color = textureSample(baseMap,baseMapSampler,uv) ;
//Store the color in the built-in variable ORI_ShadingInput's BaseColor
ORI_ShadingInput.BaseColor = color * materialUniform.baseColor ;
//Execute the unlit shading function
UnLit();
}
Put the above script into ShaderLib for management by a specific key UnLitShader
.
let Unlit:string = `${shaderCode}`;
ShaderLib.register('UnLitShader', UnLit);
Creating a ShaderRenderShader
Here, we set the vertexShader and fragmentShader as the same script.
//Create a shader instance
let shader = this.setShader(`UnLitShader`,`UnLitShader`);
//Set the entry function
shader.setShaderEntry(`VertMain`,`FragMain`)
Setting Material Variables
Materials often need to modify the rendering results of materials from the outside, which can be abstracted as variables and exposed for external use.
An unlit material may have simple UV transformation effects, default colors, transparency clipping thresholds, etc. Here, we extract four variables for external modification.
//The transformation coefficient of the first UV
shader.setUniformVector4(`transformUV1`, new Vector4(0, 0, 1, 1));
//The transformation coefficient of the second UV
shader.setUniformVector4(`transformUV2`, new Vector4(0, 0, 1, 1));
//Base color
shader.setUniformColor(`baseColor`, new Color());
//Transparency clipping threshold
shader.setUniformFloat(`alphaCutoff`, 0.5);
Configuration of Material Shader Macros
There are some common macros for material shaders that need to be explicitly set:
useLight
: whether to receive lighting influence;acceptGI
: whether to receive global illumination (GI);acceptShadow
: whether to receive shadows;castShadow
: whether to cast shadows;receiveEnv
: whether to receive environmental lighting;- ...
You may also need to set the following properties:
renderLayer
: the rendering layer it belongs to;renderOrder
: the rendering priority for transparency rendering;- ...
The macros for non-lighting material shaders are as follows:
let shaderState = shader.shaderState;
//Do not accept shadows
shaderState.acceptShadow = false;
//Do not receive environmental lighting
shaderState.receiveEnv = false;
//Do not accept global illumination
shaderState.acceptGI = false;
//Not affected by lighting
shaderState.useLight = false;
Summary
The process of customizing a material shader is generally similar to that of a non-lighting shader. During your practice, you may encounter such problems, which can be resolved by troubleshooting one by one.
- Using a built-in variable that has not been defined: check whether the corresponding code segment has been included;
- Using a built-in function that has not been defined: check whether the corresponding code segment has been included;
- Defining a variable that conflicts with a built-in variable: rename your variable to avoid conflict with the built-in variable;
- Defining a function that conflicts with a built-in function: rename your function to avoid conflict with the built-in function;
- Defining a structure that conflicts with a built-in structure: rename your structure to avoid conflict with the built-in structure;
- Incorrect macro settings lead to the use of undefined variables, functions, and structures in the code path;
- Inconsistent naming of Uniform, Texture, and GPUBuffer data bindings in the material shader with TypeScript script. Modify the naming in your shader code to be consistent with the TypeScript script.