feat: update en doc for shaderlab

This commit is contained in:
Sway007
2025-01-23 10:55:27 +08:00
parent 5542897fd1
commit 3ef643e2d9
7 changed files with 389 additions and 176 deletions

View File

@@ -1,7 +1,8 @@
{
"intro": "Introduction",
"shader": "Shader",
"editor": "Editor",
"subShader": "SubShader",
"pass": "Pass",
"macro": "Macro"
}
}

View File

@@ -0,0 +1,256 @@
import { Image } from "@/mdx";
---
# Editor
```glsl
Editor {
Properties {
material_BaseColor("Offset unit scale", Color) = (1,1,1,1);
...
Header("Emissive")
{
material_EmissiveColor("Emissive color", Color) = (1,1,1,1);
...
}
...
}
...
Macros {
[On] UV_OFFSET("UV Offset", Range(1,100)) = 10;
...
Header("") {
SOME_MACRO("label", Int) = 1;
}
}
...
// Specify the path of bound UIScript.
UIScript "./shaderScript.ts";
}
```
## Properties
It can be used to define properties bound to the Shader's custom material, allowing developers to adjust the defined properties through the custom material Inspector panel in the editor.
<Image
src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*1mjVR5GXXOkAAAAAAAAAAAAADteEAQ/fmt.webp"
figcaption="Material Inspector"
width="200px"
/>
### Property Definition
```glsl
/**
* @language zh
* Comments description
*/
/**
* @language en
* 注释描述
*/
propertyName("Description", EditType) = [DefaultValue];
```
<Callout type="info">
1. You can use the `Header` directive to organize related properties, and the corresponding Inspector will have the appropriate hierarchical categorization.
```
Header("Emissive") {
material_EmissiveColor("Emissive color", Color) = (1,1,1,1);
...
}
```
2. Annotate Inspector Hover tooltip content through comments, supporting multilingual specification using the `@language` directive.
</Callout>
The currently supported list of EditTypes is as follows::
| EditType | Example |
| :-: | :-- |
| Bool | propertyName("Property Description", Boolean) = true; |
| Int | propertyName("Property Description", Int) = 1; <br/>propertyName("Property Description", Range(0,8)) = 1 <br/> propertyName("Property Description", Enum(Item1: 1, Item2: 2, Item3: 3)) = 1 // Enumeration |
| Float | propertyName("Property Description", FLoat) = 0.5; <br/>propertyName("Property Description", Range(0.0, 1.0)) = 0.5; <br/> propertyName("Property Description", Enum(Item1: 1.0, Item2: 2.0, Item3: 3.0)) = 1.0; // Enumeration |
| Texture2D | propertyName("Property Description", Texture2D); |
| TextureCube | propertyName("Property Description", TextureCube); |
| Color | propertyName("Property Description", Color) = (0.25, 0.5, 0.5, 1); |
| Vector2 | propertyName("Property Description", Vector2) = (0.25, 0.5); |
| Vector3 | propertyName("Property Description", Vector3) = (0.25, 0.5, 0.5); |
| Vector4 | propertyName("Property Description", Vector4) = (0.25, 0.5, 0.5, 1.0); |
#### Enumeration
```glsl
propertyName("Property Description", Enum(Item1: 1, Item2: 2, Item3: 3)) = 1;
```
<Callout typ="warning">
Currently, only Int and Float types support enumeration, and type mixing is not supported. For example, the following
enumeration mixes Float and Int, and will not be correctly parsed. ```glsl propertyName("Property Description",
Enum("Item1":1, "Item2":2.0, "Item3": 3)) = 2.0; ```
</Callout>
## Macros
It is used to reflect macros utilized in the Shader to the Inspector, allowing for flexible adjustments of the macros on which the Shader depends within the editor.
```
[On/Off]macroName("MacroLabel", EditType) = [DefaultValue];
```
Specify the default state of a macro using the [On/Off] directive. The types of macros currently supported by the editor are as follows:
| Type | Example |
| :-----: | :-------------------------------------------------------------------------------------------------------- |
| | macroName("Macro Description"); |
| Bool | macroName("Macro Description", Boolean) = true; |
| Int | macroName("Macro Description", Int) = 1; <br/> macroName("Macro Description", Range(0,8)) = 1; |
| Float | macroName("Macro Description", FLoat) = 0.5; <br/> macroName("Macro Description", Range(0.0, 1.0)) = 0.5; |
| Color | macroName("Macro Description", Color) = (0.25, 0.5, 0.5, 1); |
| Vector2 | macroName("Macro Description", Vector2) = (0.25, 0.5); |
| Vector3 | macroName("Macro Description", Vector3) = (0.25, 0.5, 0.5); |
| Vector4 | macroName("Macro Description", Vector4) = (0.25, 0.5, 0.5, 1.0); |
## UIScript
While developers adjust custom material properties using the editor, they can also specify data change callback behavior through `UIScript`.
- Bind `UIScript` in ShaderLab:
```
Editor {
...
UIScript "/path/to/script";
...
}
```
<Image
src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*t4LFQ4KEL6kAAAAAAAAAAAAADteEAQ/fmt.webp"
width="70%"
/>
The bound UIScript script path supports both relative and absolute paths. Taking the project root directory in the above
image as an example, the absolute path is `/PBRScript1.ts`, and the relative path is `./PBRScript1.ts`.
### UIScript API
The editor exposes relevant APIs through the built-in `ShaderUIScript` class.
```ts
import { Color, Material, Texture, Vector2, Vector3, Vector4 } from "@galacean/engine";
type ShaderPropertyValue = number | Vector2 | Vector3 | Vector4 | Color | Texture;
type ShaderMacroValue = number | Vector2 | Vector3 | Vector4 | Color;
/**
* Script for extending `Shader` UI logic.
*/
export abstract class ShaderUIScript {
/** @internal */
_propertyCallBacks: Map<string, (material: Material, value: ShaderPropertyValue) => void> = new Map();
/** @internal */
_macroCallBacks: Map<string, (material: Material, defined: boolean, value: ShaderMacroValue) => void> = new Map();
/**
* The method is called when then shader is switched.
* @param material - The material which the shader is bound to
*/
onMaterialShaderSwitched(material: Material): void {}
/**
* Register property change callback.
* @parma propertyName - Property name
* @parma onChanged - Fired on property changed
*/
protected onPropertyChanged(
propertyName: string,
onChanged: (material: Material, value: ShaderPropertyValue) => void
): void {
this._propertyCallBacks.set(propertyName, onChanged);
}
/**
* Register macro change callback.
* @parma macroName - Macro name
* @parma onChanged - Fired on macro changed
*/
protected onMacroChanged(
macroName: string,
onChanged: (material: Material, defined: boolean, value: ShaderMacroValue) => void
): void {
this._macroCallBacks.set(macroName, onChanged);
}
}
```
### Edit UIScript
1. Create UIScript in Editor
<Image
src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*Qh4UTZgaY7MAAAAAAAAAAAAADteEAQ/fmt.webp"
width="60%"
figcaption="create UIScript"
/>
2. Specify property change callbacks by inheriting from the `ShaderUIScript` class.
```ts
import { Material, RenderQueueType, Vector3, BlendFactor, RenderFace, CullMode, BlendMode } from "@galacean/engine";
export default class extends ShaderUIScript {
constructor() {
super();
......
// Register change callbacks in constructor.
this.onPropertyChanged("material_NormalTexture", (material: Material, value) => {
const shaderData = material.shaderData;
if (value) {
shaderData.enableMacro("MATERIAL_HAS_NORMALTEXTURE");
} else {
shaderData.disableMacro("MATERIAL_HAS_NORMALTEXTURE");
}
})
......
}
// Specify callback on shader switch.
override onMaterialShaderSwitched(material: Material) {
const shaderData = material.shaderData;
shaderData.disableMacro("MATERIAL_OMIT_NORMAL");
shaderData.enableMacro("MATERIAL_NEED_WORLD_POS");
shaderData.enableMacro("MATERIAL_NEED_TILING_OFFSET");
// default value
const anisotropyInfo = shaderData.getVector3("material_AnisotropyInfo");
if (!anisotropyInfo) {
shaderData.setVector3("material_AnisotropyInfo", new Vector3(1, 0, 0));
} else {
shaderData.setFloat("anisotropy", anisotropyInfo.z);
const PI2 = Math.PI * 2;
const rotationRad = (Math.atan2(anisotropyInfo.y, anisotropyInfo.x) + PI2 ) % PI2;
shaderData.setFloat("anisotropyRotation", rotationRad * (180 / Math.PI))
}
}
}
```
<Callout info="warning">
Note that the current version of the ShaderLab material properties module only defines the Inspector UI panel for the
material bound to the Shader in the editor. It does not declare the corresponding global variables in the ShaderPass
for you. If the ShaderPass code references this variable, you must explicitly declare it in the Global Variables
module.
</Callout>

View File

@@ -8,7 +8,10 @@ Double-click the shader asset we created in the previous step to jump to the cod
> A future version will release the Galacean VSCode plugin, which will provide syntax checking, auto-completion, and code synchronization features for `ShaderLab`. Stay tuned.
<Image src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*Djs2RJsoPawAAAAAAAAAAAAADteEAQ/original" style={{zoom:"50%"}}/>
<Image
src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*c4yyRboqBSwAAAAAAAAAAAAADteEAQ/fmt.webp"
style={{ zoom: "50%" }}
/>
## Syntax Standard
@@ -17,6 +20,9 @@ The `ShaderLab` syntax framework is as follows:
```glsl
Shader "ShaderName" {
...
Editor {
...
}
SubShader "SubShaderName" {
...
Pass "PassName" {

View File

@@ -98,3 +98,32 @@ material.renderQueueType = RenderQueueType.Opaque;
When render states and render queues are declared in ShaderLab, the corresponding settings in the material will be ignored."
</Callout>
```
## MRT(Multiple Render Targets)
ShaderLab is compatible with both GLSL 100 and GLSL 300 syntax, allowing you to specify MRT using either syntax.
1. Specify MRT using `gl_FragData[i]`.
```glsl
void main(v2f input) {
gl_FragData[0] = vec4(1.,0.,0.,1.); // render target 0
gl_FragData[1] = vec4(1.,0.,0.,1.); // render target 1
}
```
2. Specify by returning a struct from the entry function
```glsl
struct mrt {
layout(location = 0) vec4 fragColor0; // render target 0
layout(location = 1) vec4 fragColor1; // render target 1
}
mrt main(v2f input) {
mrt output;
output.fragColor0 = vec4(1.,0.,0.,1.);
output.fragColor1 = vec4(1.,0.,0.,1.);
return output;
}
```

View File

@@ -18,87 +18,7 @@ In ShaderLab, `Shader` is a collection of shader programs and other engine rende
## Material Property Definition
```glsl
// Uniform
EditorProperties
{
material_BaseColor("Offset unit scale", Color) = (1,1,1,1);
...
Header("Emissive")
{
material_EmissiveColor("Emissive color", Color) = (1,1,1,1);
...
}
...
}
// Macro
EditorMacros
{
[On] UV_OFFSET("UV Offset", Range(1,100)) = 10;
...
}
```
This module is used to define the UI display of the material bound to the Shader in the editor's Inspector panel. ShaderLab material properties use `EditorProperties` and `EditorMacros` to separately declare macro properties and other Uniform properties. The declaration format is:
1. Uniform Properties
```glsl
EditorProperties {
propertyName("label in Inspector", type) [= defaultValue];
...
[ Header("blockName") {
propertyName("label in Inspector", type) [= defaultValue];
...
} ]
}
```
> Nested `Header` blocks can be used to hierarchically categorize material properties.
Supported types are
| Type | Example |
| :-: | :-- |
| Bool | propertyName("Property Description", Boolean) = true; |
| Int | propertyName("Property Description", Int) = 1; <br/>propertyName("Property Description", Range(0,8)) = 1 |
| Float | propertyName("Property Description", Float) = 0.5; <br/>propertyName("Property Description", Range(0.0, 1.0)) = 0.5; |
| Texture2D | propertyName("Property Description", Texture2D); |
| TextureCube | propertyName("Property Description", TextureCube); |
| Color | propertyName("Property Description", Color) = (0.25, 0.5, 0.5, 1); |
| Vector2 | propertyName("Property Description", Vector2) = (0.25, 0.5); |
| Vector3 | propertyName("Property Description", Vector3) = (0.25, 0.5, 0.5); |
| Vector4 | propertyName("Property Description", Vector4) = (0.25, 0.5, 0.5, 1.0); |
2. Macro Properties
```glsl
EditorMacros {
[\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue];
...
[ Header("blockName") {
[\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue];
...
} ]
}
```
All include enable and disable functions, initialized by the `[On/Off]` directive. The types include
| Type | Example |
| :-: | :-- |
| None (Toggle Macro) | macroName("Macro Description"); |
| Bool | macroName("Macro Description", Boolean) = true; |
| Int | macroName("Macro Description", Int) = 1; <br/> macroName("Macro Description", Range(0,8)) = 1; |
| Float | macroName("Macro Description", Float) = 0.5; <br/> macroName("Macro Description", Range(0.0, 1.0)) = 0.5; |
| Color | macroName("Macro Description", Color) = (0.25, 0.5, 0.5, 1); |
| Vector2 | macroName("Macro Description", Vector2) = (0.25, 0.5); |
| Vector3 | macroName("Macro Description", Vector3) = (0.25, 0.5, 0.5); |
| Vector4 | macroName("Macro Description", Vector4) = (0.25, 0.5, 0.5, 1.0); |
> Note that the current version of the ShaderLab material property module only defines the Inspector UI panel for the material bound to this Shader in the editor. It does not declare the corresponding global variables for you in the `ShaderPass`. If the `ShaderPass` code references this variable, you need to explicitly declare it in the global variable module (see below).
In ShaderLab, developers can customize the Inspector property panel for custom materials using this Shader through the [`Editor`](./editor/) directive.
## Global Variables
@@ -106,107 +26,107 @@ You can declare 4 types of global variables in ShaderLab: RenderState, Structs,
### RenderState
Includes BlendState, DepthState, StencilState, RasterState
Includes BlendState, DepthState, StencilState, RasterState
- BlendState
```glsl
BlendState {
Enabled[n]: bool;
ColorBlendOperation[n]: BlendOperation;
AlphaBlendOperation[n]: BlendOperation;
SourceColorBlendFactor[n]: BlendFactor;
SourceAlphaBlendFactor[n]: BlendFactor;
DestinationColorBlendFactor[n]: BlendFactor;
DestinationAlphaBlendFactor[n]: BlendFactor;
ColorWriteMask[n]: float // 0xffffffff
BlendColor: vec4;
AlphaToCoverage: bool;
}
```
[n] can be omitted. When using MRT, [n] specifies a particular MRT render state. Omitting it sets all MRT states. BlendOperation and BlendFactor enums are the same as the engine API.
- DepthState
```glsl
DepthState {
Enabled: bool;
WriteEnabled: bool;
CompareFunction: CompareFunction;
}
```
CompareFunction enums are the same as the engine API.
- StencilState
```glsl
StencilState {
Enabled: bool;
ReferenceValue: int;
Mask: float; // 0xffffffff
WriteMask: float; // 0xffffffff
CompareFunctionFront: CompareFunction;
CompareFunctionBack: CompareFunction;
PassOperationFront: StencilOperation;
PassOperationBack: StencilOperation;
FailOperationFront: StencilOperation;
FailOperationBack: StencilOperation;
ZFailOperationFront: StencilOperation;
ZFailOperationBack: StencilOperation;
}
```
CompareFunction and StencilOperation enums are the same as the engine API.
- RasterState
```glsl
RasterState {
CullMode: CullMode;
DepthBias: float;
SlopeScaledDepthBias: float;
}
```
CullMode enums are the same as the engine API.
Example of setting `BlendState` in `ShaderLab`:
- BlendState
```glsl
Shader "Demo" {
...
BlendState customBlendState
{
Enabled = true;
// Constant variable assignment
SourceColorBlendFactor = BlendFactor.SourceColor;
// Variable assignment
DestinationColorBlendFactor = material_DstBlend;
}
...
Pass "0" {
...
BlendState = customBlendState;
...
}
BlendState {
Enabled[n]: bool;
ColorBlendOperation[n]: BlendOperation;
AlphaBlendOperation[n]: BlendOperation;
SourceColorBlendFactor[n]: BlendFactor;
SourceAlphaBlendFactor[n]: BlendFactor;
DestinationColorBlendFactor[n]: BlendFactor;
DestinationAlphaBlendFactor[n]: BlendFactor;
ColorWriteMask[n]: float // 0xffffffff
BlendColor: vec4;
AlphaToCoverage: bool;
}
```
The above example shows two ways of assigning values to BlendState properties: *constant assignment* and *variable assignment*:
[n] can be omitted. When using MRT, [n] specifies a particular MRT render state. Omitting it sets all MRT states. BlendOperation and BlendFactor enums are the same as the engine API.
- Constant assignment means the right side of the assignment statement is a specified engine enum variable, e.g., BlendFactor.SourceColor.
- Variable assignment means the right side of the assignment statement is any variable name. The specific value of the variable is specified by the user at runtime through the ShaderData.setInt("material_DstBlend", BlendFactor.SourceColor) API.
- DepthState
```glsl
DepthState {
Enabled: bool;
WriteEnabled: bool;
CompareFunction: CompareFunction;
}
```
CompareFunction enums are the same as the engine API.
- StencilState
```glsl
StencilState {
Enabled: bool;
ReferenceValue: int;
Mask: float; // 0xffffffff
WriteMask: float; // 0xffffffff
CompareFunctionFront: CompareFunction;
CompareFunctionBack: CompareFunction;
PassOperationFront: StencilOperation;
PassOperationBack: StencilOperation;
FailOperationFront: StencilOperation;
FailOperationBack: StencilOperation;
ZFailOperationFront: StencilOperation;
ZFailOperationBack: StencilOperation;
}
```
CompareFunction and StencilOperation enums are the same as the engine API.
- RasterState
```glsl
RasterState {
CullMode: CullMode;
DepthBias: float;
SlopeScaledDepthBias: float;
}
```
CullMode enums are the same as the engine API.
Example of setting `BlendState` in `ShaderLab`:
```glsl
Shader "Demo" {
...
BlendState customBlendState
{
Enabled = true;
// Constant variable assignment
SourceColorBlendFactor = BlendFactor.SourceColor;
// Variable assignment
DestinationColorBlendFactor = material_DstBlend;
}
...
Pass "0" {
...
BlendState = customBlendState;
...
}
}
```
The above example shows two ways of assigning values to BlendState properties: _constant assignment_ and _variable assignment_:
- Constant assignment means the right side of the assignment statement is a specified engine enum variable, e.g., BlendFactor.SourceColor.
- Variable assignment means the right side of the assignment statement is any variable name. The specific value of the variable is specified by the user at runtime through the ShaderData.setInt("material_DstBlend", BlendFactor.SourceColor) API.
### Structs, Functions
Same as the syntax in GLSL.
Same as the syntax in GLSL.
### Single Variables
```glsl
[lowp/mediump/highp] variableType variableName;
```
```glsl
[lowp/mediump/highp] variableType variableName;
```
Similar to other programming languages, global variables in ShaderLab also have scope and name overriding principles. In simple terms, the scope of global variables in ShaderLab is limited to the SubShader or Pass module in which they are declared. The name overriding principle means that if there are global variables with the same name within a Pass, the global variables within the Pass will override the global variables with the same name in the SubShader.

View File

@@ -76,7 +76,7 @@ Header("Emissive") {
</Callout>
通过注释标注 Inspector Hover 提示内容,支持使用 @language 指令进行多语言指定。当前支持的 EditType 列表如下:
当前支持的 EditType 列表如下:
| EditType | Example |
| :-: | :-- |
@@ -255,6 +255,6 @@ export default class extends ShaderUIScript {
```
<Callout info="warning">
注意,当前版本 ShaderLab 材质属性模块只是定义了绑定该 Shader 的材质在编辑器中的 Inspector UI
面板,并不会替你在`ShaderPass`中声明对应的全局变量,如果`ShaderPass`代码中引用了该变量需在[全局变量](./shader/#全局变量)模块中明确声明补充。
注意,当前版本 ShaderLab 材质属性模块只是定义了绑定该 Shader 的材质在编辑器中的 Inspector
UI面板,并不会替你在`ShaderPass`中声明对应的全局变量,如果`ShaderPass`代码中引用了该变量需在[全局变量](./shader/#全局变量)模块中明确声明补充。
</Callout>

View File

@@ -109,7 +109,7 @@ void main(v2f input) {
gl_FragData[0] = vec4(1.,0.,0.,1.); // render target 0
gl_FragData[1] = vec4(1.,0.,0.,1.); // render target 1
}
````
```
2. 通过入口函数返回结构体指定
@@ -126,3 +126,4 @@ mrt main(v2f input) {
return output;
}
```
````