开发者使用编辑器对自定义材质属性进行调节的同时,还可以通过 UIScript
指令指定数据变更的回调行为。通过 UIScript 暴露的 hook 函数,开发者可以实现属性联动,从而减少声明属性的数量,达到简化 Inspector 面板的目的。
UIScript
:Editor {
...
UIScript "/path/to/script";
...
}
绑定的UIScript
脚本路径支持相对路径和绝对路径,以下图项目根目录为例,绝对路径为
/PBRScript1.ts
,相对路径为./PBRScript1.ts
编辑器通过内置 ShaderUIScript
类暴露相关 API,ShaderUIScript
的类型定义已经内嵌至 Galacean Web 端脚本编辑器中,完整定义如下:
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);
}
}
import { Material, RenderQueueType, Vector3, BlendFactor, RenderFace, CullMode, BlendMode } from "@galacean/engine";
export default class extends ShaderUIScript {
constructor() {
super();
......
// 在构造函数中注册监听属性回调
this.onPropertyChanged("material_NormalTexture", (material: Material, value) => {
const shaderData = material.shaderData;
if (value) {
shaderData.enableMacro("MATERIAL_HAS_NORMALTEXTURE");
} else {
shaderData.disableMacro("MATERIAL_HAS_NORMALTEXTURE");
}
})
......
}
// 指定 shader 绑定的回调
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))
}
}
}
注意,当前版本 ShaderLab 材质属性模块只是定义了绑定该 Shader 的材质在编辑器中的 Inspector
UI面板,并不会替你在ShaderPass
中声明对应的全局变量,如果ShaderPass
代码中引用了该变量需在全局变量模块中明确声明补充。