Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update shaderlab doc #2505

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
* 注释描述
*/
Comment on lines +46 to +54
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix swapped language descriptions in comments.

The multilingual comments have their descriptions in the wrong language sections. The Chinese description appears under the English tag and vice versa.

 /**
  * @language zh
- * Comments description
+ * 注释描述
  */

 /**
  * @language en
- * 注释描述
+ * Comments description
  */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @language zh
* Comments description
*/
/**
* @language en
* 注释描述
*/
/**
* @language zh
* 注释描述
*/
/**
* @language en
* Comments description
*/

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>
Comment on lines +93 to +97
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in Callout component attribute.

The Callout component has a typo in its type attribute (typ instead of type).

-<Callout typ="warning">
+<Callout type="warning">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<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>
<Callout type="warning">
Currently, only Int and Float types support enumeration, and type mixing is not supported. For example, the following


## 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 {
...
}
Comment on lines +23 to +25
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Add link to Editor block documentation

The Editor block documentation exists at editor.mdx in the same directory, but there's no link to it from the introduction. Add a reference to help users find the detailed documentation.

🔗 Analysis chain

Verify Editor block documentation

The Editor block is introduced in the syntax framework, but ensure that there's a corresponding link to its detailed documentation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if Editor documentation exists
fd -t f "editor.mdx" docs/en/graphics/shader/shaderLab/syntax/

Length of output: 114


Script:

#!/bin/bash
# Check intro.mdx for links to editor documentation
cat docs/en/graphics/shader/shaderLab/syntax/intro.mdx | grep -i "editor" -A 2 -B 2

Length of output: 272

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
Loading