Skip to content

Commit

Permalink
Merge pull request #2505 from Sway007/doc/shaderlab
Browse files Browse the repository at this point in the history
Update shaderlab doc
  • Loading branch information
eyworldwide authored Jan 23, 2025
2 parents 1d6264d + 13fde20 commit 7fc8cc7
Show file tree
Hide file tree
Showing 10 changed files with 683 additions and 255 deletions.
3 changes: 2 additions & 1 deletion docs/en/graphics/shader/shaderLab/syntax/_meta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"intro": "Introduction",
"shader": "Shader",
"editor": "Editor",
"subShader": "SubShader",
"pass": "Pass",
"macro": "Macro"
}
}
256 changes: 256 additions & 0 deletions docs/en/graphics/shader/shaderLab/syntax/editor.mdx
Original file line number Diff line number Diff line change
@@ -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>
8 changes: 7 additions & 1 deletion docs/en/graphics/shader/shaderLab/syntax/intro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -17,6 +20,9 @@ The `ShaderLab` syntax framework is as follows:
```glsl
Shader "ShaderName" {
...
Editor {
...
}
SubShader "SubShaderName" {
...
Pass "PassName" {
Expand Down
29 changes: 29 additions & 0 deletions docs/en/graphics/shader/shaderLab/syntax/pass.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
```
Loading

0 comments on commit 7fc8cc7

Please sign in to comment.