diff --git a/docs/zh/graphics/material/material.md b/docs/zh/graphics/material/material.md index f011d6233..daac1a578 100644 --- a/docs/zh/graphics/material/material.md +++ b/docs/zh/graphics/material/material.md @@ -12,6 +12,6 @@ label: Graphics/Material 本节包含以下相关信息: -- [材质组成](/docs/graphics-material-composition) -- [编辑器使用](/docs/graphics-material-editor) -- [脚本使用](/docs/graphics-material-script) +- [材质组成](./composition) +- [编辑器使用](./editor) +- [脚本使用](./script) diff --git a/docs/zh/graphics/shader/_meta.json b/docs/zh/graphics/shader/_meta.json new file mode 100644 index 000000000..d3ee0be69 --- /dev/null +++ b/docs/zh/graphics/shader/_meta.json @@ -0,0 +1,8 @@ +{ + "intro": {"title": "着色器简介"}, + "class": {"title": "Shader 对象"}, + "builtins": {"title": "内置着色器"}, + "custom": {"title": "自定义着色器"}, + "assets": {"title": "Shader 资产"}, + "shaderLab": {"title": "ShaderLab"} +} \ No newline at end of file diff --git a/docs/zh/graphics/shader/assets.mdx b/docs/zh/graphics/shader/assets.mdx new file mode 100644 index 000000000..c57df7870 --- /dev/null +++ b/docs/zh/graphics/shader/assets.mdx @@ -0,0 +1,23 @@ +--- +title: Shader 资产 +--- + +Shader 资产是 Galacean 编辑器项目中定义 Shader 对象的资产,目前包含两种: + +- Shader 主文件 + +以 `.gs` 为后缀名,是 ShaderLab 编译的入口文件。 + +- Shader Chunk + +以 `.glsl` 为后缀名,是可以复用的 ShaderLab 代码片段,通过 `#include` 宏引入。 + + +`EditorProperties` 和 `EditorMacros` 只能声明在 Shader 主文件内,不能声明在 Shader 文件片段中,通过 `#include` 宏引入。 + + +## Shader 资产创建 + + + +编辑器中可以提供了3个 Shader 资产文件模板: `Unlit` Shader, `Pbr` Shader 和 Shader Chunk。和脚本组件类似,选中 Shader 资产可以在 Inspector 界面预览 Shader 代码,双击或者在代码编辑页面选中可以实时编辑 Shader 代码。 diff --git a/docs/zh/graphics/shader/builtins/_meta.json b/docs/zh/graphics/shader/builtins/_meta.json new file mode 100644 index 000000000..5d7e4cf14 --- /dev/null +++ b/docs/zh/graphics/shader/builtins/_meta.json @@ -0,0 +1,6 @@ +{ + "intro": {"title": "介绍"}, + "pbr": "PBR", + "unlit": "Unlit", + "blinnPhong": "Blinn Phong" +} \ No newline at end of file diff --git a/docs/zh/graphics/shader/blinnPhong.md b/docs/zh/graphics/shader/builtins/blinnPhong.md similarity index 98% rename from docs/zh/graphics/shader/blinnPhong.md rename to docs/zh/graphics/shader/builtins/blinnPhong.md index 2bb30d079..e2572d41d 100644 --- a/docs/zh/graphics/shader/blinnPhong.md +++ b/docs/zh/graphics/shader/builtins/blinnPhong.md @@ -1,9 +1,5 @@ --- -order: 3 title: Blinn Phong -type: 着色器 -group: 网格 -label: Graphics/Shader --- [BlinnPhongMaterial](/apis/core/#BlinnPhongMaterial) 虽然不是基于物理渲染,但是其高效的渲染算法和基本齐全的光学部分,流传至今仍可以适用很多的场景。 diff --git a/docs/zh/graphics/shader/builtins/intro.mdx b/docs/zh/graphics/shader/builtins/intro.mdx new file mode 100644 index 000000000..de39cb9cd --- /dev/null +++ b/docs/zh/graphics/shader/builtins/intro.mdx @@ -0,0 +1,25 @@ +--- +title: 介绍 +--- + +目前Galacean引擎内置了许多常用的Shader,诸如 + +| 类型 | 描述 | +| :-- | :-- | +| [Unlit ](./unlit) | Unlit 材质适用于烘焙好的模型渲染,她只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响,可参考 [烘焙教程](/docs/graphics-bake-blender) 和 [导出 Unlit 教程](./unlit) | +| [Blinn Phong ](./blinnPhong) | Blinn Phong 材质适用于那些对真实感没有那么高要求的场景,虽然没有遵循物理,但是其高效的渲染算法和基本齐全的光学部分,可以适用很多的场景。 | +| [PBR ](./pbr) | PBR 材质适合需要真实感渲染的应用场景,因为 PBR 是基于物理的渲染,遵循能量守恒,开发者通过调整金属度、粗糙度、灯光等参数,能够保证渲染效果都是物理正确的。 | + +可以在编辑器中直接调试内置着色器的对应属性观察实时渲染效果变化。 + + + +> 与之对应的,也可以通过设置 PBRMaterial , BlinnPhongMaterial 与 UnlitMaterial 材质的 API 达到相同效果。 + +| 参数 | 应用 | +| :-- | :-- | +| [isTransparent](/apis/core/#BaseMaterial-isTransparent) | 是否透明。可以设置材质是否透明。如果设置为透明,可以通过 [BlendMode](/apis/core/#BaseMaterial-blendMode) 来设置颜色混合模式。 | +| [alphaCutoff](/apis/core/#BaseMaterial-alphaCutoff) | 透明度裁剪值。可以设置裁剪值,在着色器中,透明度小于此数值的片元将会被裁减,参考 [案例](${examples}blend-mode) | +| [renderFace](/apis/core/#BaseMaterial-renderFace) | 渲染面。可以决定渲染正面、背面、双面。 | +| [blendMode](/apis/core/#BaseMaterial-blendMode) | 颜色混合模式。当设置材质为透明后,可以设置此枚举来决定颜色混合模式,参考 [案例](${examples}blend-mode) | +| [tilingOffset](/apis/core/#BlinnPhongMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](${examples}tiling-offset) | \ No newline at end of file diff --git a/docs/zh/graphics/shader/pbr.md b/docs/zh/graphics/shader/builtins/pbr.md similarity index 99% rename from docs/zh/graphics/shader/pbr.md rename to docs/zh/graphics/shader/builtins/pbr.md index 833425521..88414ab2e 100644 --- a/docs/zh/graphics/shader/pbr.md +++ b/docs/zh/graphics/shader/builtins/pbr.md @@ -1,9 +1,5 @@ --- -order: 1 title: PBR -type: 着色器 -group: 网格 -label: Graphics/Shader --- PBR 全称是 **Physically Based Rendering**,中文意思是**基于物理的渲染**,最早由迪士尼在 2012 年提出,后来被游戏界广泛使用。跟传统的 **Blinn-Phong** 等渲染方法相比,PBR 遵循能量守恒,符合物理规则,美术们只需要调整几个简单的参数,即使在复杂的场景中也能保证正确的渲染效果。PBR 遵循能量守恒,是基于物理的渲染,并且引入了 [IBL](/docs/graphics-light-ambient) 模拟全局光照,通过金属度、粗糙度等参数,更加方便地调节渲染效果。 diff --git a/docs/zh/graphics/shader/unlit.md b/docs/zh/graphics/shader/builtins/unlit.md similarity index 98% rename from docs/zh/graphics/shader/unlit.md rename to docs/zh/graphics/shader/builtins/unlit.md index 56bc79ad7..a747c1fde 100644 --- a/docs/zh/graphics/shader/unlit.md +++ b/docs/zh/graphics/shader/builtins/unlit.md @@ -1,9 +1,5 @@ --- -order: 2 title: Unlit -type: 着色器 -group: 网格 -label: Graphics/Shader --- 在一些简单的场景中,可能不希望计算光照,引擎提供了 [UnlitMaterial](/apis/core/#UnlitMaterial),使用了最精简的 shader 代码,只需要提供颜色或者纹理即可渲染。Unlit 材质适用于烘焙好的模型渲染,它只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响。 diff --git a/docs/zh/graphics/shader/class.mdx b/docs/zh/graphics/shader/class.mdx new file mode 100644 index 000000000..5b1818443 --- /dev/null +++ b/docs/zh/graphics/shader/class.mdx @@ -0,0 +1,55 @@ +--- +title: Shader +--- + +在[着色器简介](../intro)我们了解了着色器的基本概念,Galacean 引擎基于着色器程序,将其他渲染相关的信息进行了统一封装,形成了 Shader 对象。Shader 对象和 [材质](../../material/material)共同决定了被渲染物体最终的渲染结果。 + + +## Shader + +Shader 对象包含以下内容: + +- name + +Shader 实例对象名。Shader 对象创建后会被引擎缓存,后续复用可以通过 `Shader.find()` 以 `Shader.name` 为索引进行查找,因此,引擎规定在单个引擎实例下,Shader 的 name 属性必须唯一。 + +- SubShader + +一个 Shader 对象包含至少一个 SubShader 对象。 + +## SubShader + +一个着色器程序可能会运行在不同的GPU硬件平台、不同的渲染管线中,因此 Shader 对象通过 tags 键值对的方式为不同的硬件平台、渲染管线指定不同的渲染逻辑,即 SubShader 对象。 + +SubShader 包含以下内容: + +- Tags + +Tags 是用于被渲染管线消费的 key-value 键值对,通常用于指定 Shader 兼容的硬件平台、渲染管线等信息,当前引擎内置管线消费的 Tags 有 + +|Key|value| +|--|--| +|pipelineStage|Forward| +|pipelineStage|DepthOnly| +|pipelineStage|ShadowCaster| +|pipelineStage|DepthOnly| + +此外还可以通过 [Camera.setReplacementShader](/engine/apis/galacean/#Camera-resetReplacementShader),指定渲染管线的`replacementTag`,实现对设置指定 `Tag` 的 `SubShader` 替换的目的。 + +Tags可以通过 [SubShader.setTag](/engine/apis/galacean/#SubShader-setTag) 和 [ShaderPass.setTag](/engine/apis/galacean/#ShaderPass-setTag)进行指定,ShaderLab指定Tag方式详见[文档](./lab) + +- Passes + +一个 SubShader 包含至少一个 ShaderPass 对象。 + +- RenderStates + +SubShader 下所有 ShaderPass 共享的 [RenderState 渲染状态](../../material/composition/#渲染状态) + +## ShaderPass + +ShaderPass 封装了具体的着色器程序,以及执行最终渲染时的[渲染状态](../../material/composition/#渲染状态)。 + + +同一 SubShader 下的 ShaderPass 按照数组顺序依次渲染,渲染效果逐步叠加,形成 Shader 在当前帧的最终渲染结果。 + diff --git a/docs/zh/graphics/shader/custom.md b/docs/zh/graphics/shader/custom.md index 70023fe60..1b73442ff 100644 --- a/docs/zh/graphics/shader/custom.md +++ b/docs/zh/graphics/shader/custom.md @@ -43,7 +43,7 @@ Shader.create("demo", vertexSource, fragmentSource); const material = new Material(engine, Shader.find("demo")); ``` -`Shader.create()`用来将 shader 添加到引擎的缓存池子中,因此整个 runtime 只需要创建一次,接下来就可以通过 [Shader.find(name)](/apis/core/#Shader-find) 来反复使用. +`Shader.create()`用来将 shader 添加到引擎的缓存池子中,因此整个 runtime 只需要创建一次,接下来就可以通过 [Shader.find(name)](/engine/apis/galacean/#Shader-find) 来反复使用. > 注:引擎已经预先 create 了 blinn-phong、pbr、shadow-map、shadow、skybox、framebuffer-picker-color、trail。用户可以直接使用这些内置 shader,并且不能重名创建。 diff --git a/docs/zh/graphics/shader/intro.mdx b/docs/zh/graphics/shader/intro.mdx new file mode 100644 index 000000000..4581281e4 --- /dev/null +++ b/docs/zh/graphics/shader/intro.mdx @@ -0,0 +1,25 @@ + + +## 着色器简介 + +着色器(Shader)是一段运行在GPU中的程序,通常由2个“入口函数”组成,我们称之为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader),分别对应于渲染管线的两个不同阶段。下面是一幅简化的引擎渲染过程(渲染管线)的图示,我们聚焦于着色器部分进行描述 + +```mermaid +flowchart LR + A[CPU应用层] -->|准备顶点和其他\n渲染计算相关的数据| B{Vertex Shader} + subgraph Shader / 着色器 + B --> |计算顶点在三维空间的真实坐标\n以及其他后续渲染阶段需要的数据| C{Fragment Shader} + end + C -->|基于上一个渲染阶段的计算结果数据\n计算每个顶点的最终像素值| D[帧图像] +``` + +
简化的渲染管线
+ +本章节我们将介绍如下内容: +|小节|内容| +|:--:|:--:| +|[Shader对象](./class)|引擎中Shader对象的概括和基本用法| +|[内置着色器](./builtins/intro)|引擎内置的常用着色器| +|[Shader资产](./assets)|在编辑器中如何创建、修改Shader资产| +|[ShaderLab](./lab)|一种更为便捷的创建Shader的方式| + diff --git a/docs/zh/graphics/shader/lab.md b/docs/zh/graphics/shader/lab.md deleted file mode 100644 index ef0441eab..000000000 --- a/docs/zh/graphics/shader/lab.md +++ /dev/null @@ -1,484 +0,0 @@ ---- -order: 5 -title: Shader Lab -type: 着色器 -group: 网格 -label: Graphics/Shader ---- - -`ShaderLab` 是一个针对 Galacean 引擎打造的 Shader 包装语言,它允许开发人员使用熟悉的 [GLSL](https://www.khronos.org/files/opengles_shading_language.pdf) 语法编写自定义 Shader,同时提供了额外的高级抽象和管理特性以增强开发效率。通过 ShaderLab,开发者能够更便捷地定义材质属性、渲染配置和其他效果。尽管 ShaderLab 为着色器的编写引入了便利性,但它并不取代 GLSL,而是与之兼容。开发者可以在 ShaderLab 框架内编写原生 GLSL 代码块,享受两者的结合优势。ShaderLab 使用流程如下: - -```mermaid -flowchart LR - 创建着色器 --> 编辑shaderlab --> 调试shaderlab -``` - -以下是一个简单的 ShaderLab 使用示例,其中包含了两个 Shader。`normal` Shader 定义了一个只实现 MVP 转换的顶点着色器,并且通过 Uniform 变量指定了像素颜色的片元着色器。另外,`lines` Shader 是一个使用 ShaderLab 进行改造的 [shadertoy](https://www.shadertoy.com/view/DtXfDr) 示例。 - - - -## 创建着色器 - -#### 在编辑器中创建 - -编辑器中可以添加 3 种 ShaderLab 模板: 自定义、`PBR`、和 着色器片段 - - - -其中 **自定义** 和 **`PBR`** 是使用 ShaderLab 语法进行编写的着色器模板,**着色器片段** 则是为了方便代码段复用,ShaderLab 中可以如下使用 `include` 宏进行代码段引用,后续编译过程中会被自动扩展替换。使用方式详见语法标准模块。 - -#### 在脚本中创建 - -当前`ShaderLab`尚未集成到引擎 core 核心包中,需要在引擎初始化时传入新建的`ShaderLab`对象,否则引擎无法解析使用`ShaderLab`语法编写的 Shader。 - -1. `ShaderLab` 初始化 - -```ts -import { ShaderLab } from '@galacean/engine-shaderlab'; - -const shaderLab = new ShaderLab(); -// 使用ShaderLab初始化Engine -const engine = await WebGLEngine.create({ canvas: 'canvas', shaderLab }); -``` - -2. 创建 Shader - -```glsl -// 直接使用ShaderLab创建Shader -const shader = Shader.create(galaceanShaderCode); -``` - -## `ShaderLab`编写 - -### 在编辑器中编辑着色器 - -双击我们在上一步创建的着色器资产即可跳转到代码编辑页 - -> 未来版本会推出 Galacean VSCode 插件,该插件会为`ShaderLab`提供语法检测和自动补全功能以及代码同步功能,敬请期待 - - - -### 语法标准 - -`ShaderLab`语法骨架如下,每个模块语法和使用会在下文详细展开。 - -```glsl -Shader "ShaderName" { - ... - SubShader "SubShaderName" { - ... - Pass "PassName" { - ... - } - ... - } - ... -} -``` - -#### Shader - -```glsl -Shader "ShaderName" { - ... - // 全局变量区:变量声明,结构体声明,渲染状态声明,材质属性定义 - ... - SubShader "SubShaderName" { - ... - } - ... -} -``` - -ShaderLab 中的`Shader`是传统渲染管线中着色器程序和其他引擎渲染设置相关信息的集合封装,它允许在同一个`Shader`对象中定义多个着色器程序,并告诉 Galacean 在渲染过程中如何选择使用它们。`Shader` 对象具有嵌套的结构,包含 `SubShader` 和 `Pass` 子结构。 - -#### 材质属性定义 - -```glsl -// Uniform -EditorProperties -{ - material_BaseColor("Offset unit scale", Color) = (1,1,1,1); - ... - - Header("Emissive") - { - material_EmissiveColor("Emissive color", Color) = (1,1,1,1); - ... - } - ... -} - -// 宏 -EditorMacros -{ - [On] UV_OFFSET("UV Offset", Range(1,100)) = 10; - ... -} -``` - -此模块用于定义绑定该 Shader 的材质在编辑器 Inspector 面板中的 UI 展示。ShaderLab 材质属性对宏属性和其它 Uniform 属性使用`EditorProperties`和`EditorMacros`进行分开声明,其声明格式为: - -1. Uniform 属性 - - ```glsl - EditorProperties { - propertyName("label in Inspector", type) [= defaultValue]; - ... - [ Header("blockName") { - propertyName("label in Inspector", type) [= defaultValue]; - ... - } ] - } - ``` - - > 可以使用嵌套`Header`块对材质属性进行层级分类。 - - 支持的类型有 - - | Type | Example | - | :-: | :-- | - | Bool | propertyName("Property Description", Boolean) = true; | - | Int | propertyName("Property Description", Int) = 1;
propertyName("Property Description", Range(0,8)) = 1 | - | Float | propertyName("Property Description", FLoat) = 0.5;
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. 宏属性 - - ```glsl - EditorMacros { - [\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue]; - ... - [ Header("blockName") { - [\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue]; - ... - } ] - } - ``` - - 均包含开启和禁用功能,初始化通过 `[On/Off]` 指令指定,其类型包含 - - | Type | Example | - | :-: | :-- | - | 无(开关宏) | macroName("Macro Description"); | - | Bool | macroName("Macro Description", Boolean) = true; | - | Int | macroName("Macro Description", Int) = 1;
macroName("Macro Description", Range(0,8)) = 1; | - | Float | macroName("Macro Description", FLoat) = 0.5;
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); | - -> 注意,当前版本 ShaderLab 材质属性模块只是定义了绑定该 Shader 的材质在编辑器中的 Inspector UI 面板,并不会替你在`ShaderPass`中声明对应的全局变量,如果`ShaderPass`代码中引用了该变量需在全局变量模块(见下文)中明确声明补充。 - -#### 全局变量 - -可以在 ShaderLab 中声明 4 类全局变量:渲染状态(RenderState),结构体,函数,以及单变量。 - -- 渲染状态 - - 包含混合状态(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] 可省略,在使用 MRT 的情况下, [n] 为指定某个 MRT 渲染状态,省略为设置所有 MRT 状态,BlendOperation 和 BlendFactor 枚举等同引擎 API - - - DepthState - - ```glsl - DepthState { - Enabled: bool; - WriteEnabled: bool; - CompareFunction: CompareFunction; - } - ``` - - CompareFunction 枚举等同引擎 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 和 StencilOperation 举等同引擎 API - - - RasterState - - ```glsl - RasterState { - CullMode: CullMode; - DepthBias: float; - SlopeScaledDepthBias: float; - } - ``` - - CullMode 举等同引擎 API - - 在`ShaderLab`中设置`BlendState`示例: - - ```glsl - Shader "Demo" { - ... - BlendState customBlendState - { - Enabled = true; - // 常量复制方式 - SourceColorBlendFactor = BlendFactor.SourceColor; - // 变量赋值方式 - DestinationColorBlendFactor = material_DstBlend; - } - ... - Pass "0" { - ... - BlendState = customBlendState; - ... - } - } - ``` - - 上述案例中对于 BlendState 属性赋值展示了 2 种方式: *常量赋值*和*变量赋值*方式: - - - 常量赋值指赋值语句右端为指定的对应引擎枚举变量,譬如:BlendFactor.SourceColor - - 变量赋值指赋值语句右端为任一变量名,变量具体值由用户通过脚本方式在运行时通过 ShaderData.setInt("material_DstBlend", BlendFactor.SourceColor) API 进行指定 - -- 结构体、函数 - - 等同 glsl 中的语法 - -- 单变量 - - ```glsl - [lowp/mediump/highp] variableType variableName; - ``` - -与其他编程语言类似,ShaderLab 中的全局变量也有作用域和同名覆盖原则。简单来说,ShaderLab 中的全局变量的作用范围仅限于其声明的 SubShader 或 Pass 模块内部,而同名覆盖原则指的是如果存在与 Pass 内部同名的全局变量,则 Pass 内的全局变量会覆盖 SubShader 内的同名全局变量。 - -#### SubShader - -```glsl -SubShader "SubShaderName" { - ... - // 全局变量区:变量声明,结构体声明,渲染状态声明 - ... - Tags {ReplaceTag = "opaque"} - - UsePass "ShaderName/SubShaderName/PassName" - - Pass "PassName" { - ... - } -} -``` - -一个`Shader`对象可以包含多个,但至少一个`SubShader`。它表示一组渲染管线的具体实现,定义了一种渲染效果的多个实现步骤(Pass),当前`SubShader`可以通过自定义 Tag,如`ReplaceTag`,搭配 [`Camera.setReplacementShader`](/apis/core/#Camera) 指定可能需要替换的着色器程序。 - -- `UsePass` 指令 - - 如果一个 `SubShader` 包含多个 `Pass`,可以通过 `UsePass` 指令复用其他 `Pass` 对象,比如引擎内置的 PBR Pass: `UsePass "pbr/Default/Forward"` - - | 内置 Shader | Pass 路径 | - | :-------------: | :-----------------------------: | - | PBR | pbr/Default/Forward | - | Unlit | unlit/Default/Forward | - | Skybox | skybox/Default/Forward | - | Particle-shader | particle-shader/Default/Forward | - | SpriteMask | SpriteMask/Default/Forward | - | Sprite | Sprite/Default/Forward | - -#### Pass - -```glsl -Pass "PassName" { - Tag {PipelineStage = "ShadowCaster"} - - ... - // 全局变量区:公共变量声明,结构体声明,函数声明 - ... - - // 渲染管线和渲染状态设置 - - // 指定顶点着色器和片元着色器 强调glsl语言 - VertexShader = vert; - - // 指定渲染队列 - RenderQueueType = RenderQueueType.Transparent; -} -``` - -`Pass` 是 `Shader` 对象的基本元素。简单的着色器对象可能只包含一个 `Pass`,但更复杂的着色器可以包含多个 `Pass`。 它定义了渲染管线特定阶段执行的操作,例如在 GPU 上运行的着色器程序,渲染状态,以及渲染管线相关设置。 - -- 渲染状态指定 - - 可以通过以下两种方式指定 - - 1. 显示赋值 - - ``` - BlendState = blendState; - ``` - - 2. Pass 全局变量域中声明指定 - - ``` - BlendState blendState { - 渲染状态属性 = 属性值; - } - ``` - -- uniform 变量指定 - - 直接声明成全局变量 - - ```glsl - mediump vec4 u_color; - float material_AlphaCutoff; - mat4 renderer_ModelMat; - vec3 u_lightDir; - ``` - -- attribute 变量声明 - - 通过定义顶点着色器函数入参结构体指定 - - ```glsl - struct a2v { - vec4 POSITION; - } - - v2f vert(a2v o) { - ... - } - ``` - -- varying 变量声明 - - 通过定义顶点着色器出参结构体和片元着色器入参结构体指定 - - ```glsl - struct v2f { - vec3 color; - } - - v2f vert(a2v o) { - ... - } - void frag(v2f i) { - ... - } - ``` - -- 顶点、片元着色器指定 - - 通过`VertexShader`和`FragmentShader`指定显示指定着色器入口函数 - - ``` - VertexShader = vert; - FragmentShader = frag; - ``` - -- 渲染队列设置 - - 通过`RenderQueueType`指令指定,`RenderQueueType`等同与引擎 API。 - - ``` - RenderQueueType = RenderQueueType.Transparent; - ``` - -#### `include` 宏 - -为了方便代码段复用,ShaderLab 中可以如下使用 `include` 宏进行代码段引用,后续编译过程中会被自动扩展替换。 - -```glsl -#include "{includeKey}" -``` - -为了能使代码段可以通过 `include` 宏进行引用,我们有 2 种方式进行代码段声明: - -1. 编辑器中创建 着色器 / 着色器片段 - -创建的代码段 `includeKey` 为该文件在工程中的文件路径,比如 `/Root/Effect.glsl` - -2. 脚本中显示注册代码段 - -```ts -import { ShaderFactory } from '@galacean/engine'; - -const commonSource = `// shader chunk`; -ShaderFactory.registerInclude('includeKey', commonSource); -``` - -#### 当前不支持的 GLSL 语法格式 - -1. 浮点数小数点前后的 0 不能省略 - - - ❌ `float n = 1. + .9;` - - ✅ `float n = 1.0 + 0.9;` - -2. 变量赋值语句中当赋值为函数调用返回值的属性时,需要用括弧包含函数调用 - - - ❌ `float a3 = texture2D(u_texture, (p.xy * 0.4 + um) * u_water_scale).x;` - - ✅ `float a3 = (texture2D(u_texture, (p.xy * 0.4 + um) * u_water_scale)).x;` - -3. if / for 判断语句后如果只有一行代码,"{}"不能省略 - - - ❌ - ``` - if(dis < EPS || dis > MAX_DIS) - break; - ``` - - ✅ - ``` - if(dis < EPS || dis > MAX_DIS) { - break; - } - ``` - -## 材质绑定着色器 - -有了使用`ShaderLab`编写的自定义着色器资产后,我们可以通过将着色器绑定到新建的材质实现用户自定义材质。 - - - -- `ShaderLab`反射材质属性 - -如果我们在`ShaderLab`中编写了`材质属性定义`模块,模块中定义的属性会暴露在绑定该 Shader 的材质资产 Inspector 面板中 - - - -## 一个利用多 Pass 技术实现平面阴影的示例 - - diff --git a/docs/zh/graphics/shader/shader.md b/docs/zh/graphics/shader/shader.md deleted file mode 100644 index 28630b48e..000000000 --- a/docs/zh/graphics/shader/shader.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -order: 0 -title: 着色器总览 -type: 着色器 -group: 网格 -label: Graphics/Shader ---- - -在[材质教程](/docs/graphics-material-composition) 中提到,着色器可以编写顶点、片元代码来决定渲染管线输出到屏幕上像素的颜色。 - -image-20240206153815596 - -本节包含以下相关信息: - -- 内置着色器 - - [PBR](/docs/graphics-shader-pbr) - - [Unlit](/docs/graphics-shader-unlit) - - [Blinn Phong](/docs/graphics-shader-blinnPhong) -- [自定义着色器](/docs/graphics-shader-custom) -- [Shader Lab](/docs/graphics-shader-lab) - - -```glsl -const float PI = 3.1415926535897932384626433832795; - -uniform vec3 lightDirection; -uniform vec3 lightColour; -uniform vec2 lightBias; -uniform mat4 projectionViewMatrix; - -vec3 calcSpecularLighting(vec3 toCamVector, vec3 toLightVector, vec3 normal){ - vec3 reflectedLightDirection = reflect(-toLightVector, normal); - float specularFactor = dot(reflectedLightDirection , toCamVector); - specularFactor = max(specularFactor,0.0); - specularFactor = pow(specularFactor, shineDamper); - return specularFactor * specularReflectivity * lightColour; -} - -void main(void){ - - vec3 currentVertex = vec3(in_position.x, height, in_position.y); - vec3 vertex1 = currentVertex + vec3(in_indicators.x, 0.0, in_indicators.y); - vec3 vertex2 = currentVertex + vec3(in_indicators.z, 0.0, in_indicators.w); -} -``` - -## 内置着色器 - -| 类型 | 描述 | -| :-- | :-- | -| [Unlit ](/docs/graphics-material-Unlit) | Unlit 材质适用于烘焙好的模型渲染,她只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响,可参考 [烘焙教程](/docs/graphics-bake-blender) 和 [导出 Unlit 教程](/docs/graphics-material-Unlit) | -| [Blinn Phong ](/docs/graphics-material-BlinnPhong) | Blinn Phong 材质适用于那些对真实感没有那么高要求的场景,虽然没有遵循物理,但是其高效的渲染算法和基本齐全的光学部分,可以适用很多的场景。 | -| [PBR ](/docs/graphics-material-PBR) | PBR 材质适合需要真实感渲染的应用场景,因为 PBR 是基于物理的渲染,遵循能量守恒,开发者通过调整金属度、粗糙度、灯光等参数,能够保证渲染效果都是物理正确的。 | - -以下属性在内置着色器中可以直接使用。 - -image-20240206173751409 - -| 参数 | 应用 | -| :-- | :-- | -| [isTransparent](/apis/core/#BaseMaterial-isTransparent) | 是否透明。可以设置材质是否透明。如果设置为透明,可以通过 [BlendMode](/apis/core/#BaseMaterial-blendMode) 来设置颜色混合模式。 | -| [alphaCutoff](/apis/core/#BaseMaterial-alphaCutoff) | 透明度裁剪值。可以设置裁剪值,在着色器中,透明度小于此数值的片元将会被裁减,参考 [案例](${examples}blend-mode) | -| [renderFace](/apis/core/#BaseMaterial-renderFace) | 渲染面。可以决定渲染正面、背面、双面。 | -| [blendMode](/apis/core/#BaseMaterial-blendMode) | 颜色混合模式。当设置材质为透明后,可以设置此枚举来决定颜色混合模式,参考 [案例](${examples}blend-mode) | -| [tilingOffset](/apis/core/#BlinnPhongMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](${examples}tiling-offset) | diff --git a/docs/zh/graphics/shader/shaderLab/_meta.json b/docs/zh/graphics/shader/shaderLab/_meta.json new file mode 100644 index 000000000..e838ec343 --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/_meta.json @@ -0,0 +1,6 @@ +{ + "intro": "介绍", + "create": "创建", + "syntax": "语法标准", + "usage": "使用" +} \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/create.mdx b/docs/zh/graphics/shader/shaderLab/create.mdx new file mode 100644 index 000000000..5ae97894b --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/create.mdx @@ -0,0 +1,32 @@ +--- +title: 创建 +--- + +## 在编辑器中创建 + +编辑器中可以添加 3 种 ShaderLab 模板: `Unlit`、`PBR`、和 着色器片段 + + + +其中 **`Unlit`** 和 **`PBR`** 是使用 ShaderLab 语法进行编写的着色器模板,**着色器片段** 则是为了方便代码段复用,ShaderLab 中可以如下使用 `include` 宏进行代码段引用,后续编译过程中会被自动扩展替换。使用方式详见语法标准模块。 + +## 在脚本中创建 + +当前`ShaderLab`尚未集成到引擎 core 核心包中,需要在引擎初始化时传入新建的`ShaderLab`对象,否则引擎无法解析使用`ShaderLab`语法编写的 Shader。 + +1. `ShaderLab` 初始化 + +```ts +import { ShaderLab } from '@galacean/engine-shaderlab'; + +const shaderLab = new ShaderLab(); +// 使用ShaderLab初始化Engine +const engine = await WebGLEngine.create({ canvas: 'canvas', shaderLab }); +``` + +2. 创建 Shader + +```glsl +// 直接使用 ShaderLab 创建 Shader +const shader = Shader.create(galaceanShaderCode); +``` \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/intro.md b/docs/zh/graphics/shader/shaderLab/intro.md new file mode 100644 index 000000000..5d9e828ce --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/intro.md @@ -0,0 +1,18 @@ +--- +title: ShaderLab +--- + +> 在[自定义着色器](./custom)章节我们了解到如何使用 WebGL 原生 GLSL 语言创建自定义 Shader,本节我们将介绍另一种创建 Shader 的方式 --- ShaderLab。 + +`ShaderLab` 是一个针对 Galacean 引擎打造的 Shader 包装语言,它允许开发人员使用熟悉的 [GLSL](https://www.khronos.org/files/opengles_shading_language.pdf) 语法编写自定义 Shader,同时提供了额外的高级抽象和管理特性以增强开发效率。在[材质组成](../material/composition/)章节我们提到,未引入 ShaderLab 前各类[渲染状态](./material/composition/#渲染状态)的设置需要开发者手动调用 api 进行设置,有了 ShaderLab 后,开发者能够直接在 "Shader" 文件中对渲染状态进行设置和指定,此外还能定义绑定 Shader 的材质渲染参数,映射到编辑器的 Inspector 面板中,方便开发者即时调整渲染效果。 + +尽管 ShaderLab 为着色器的编写引入了便利性,但它并不取代 GLSL,而是与之兼容。开发者可以在 ShaderLab 框架内编写原生 GLSL 代码块,享受两者的结合优势。ShaderLab 使用流程如下: + +```mermaid +flowchart LR + 创建着色器 --> 编辑 shaderlab --> 调试 shaderlab +``` + +以下是一个简单的 ShaderLab 使用示例,其中包含了两个 Shader。`normal` Shader 定义了一个只实现 MVP 转换的顶点着色器,并且通过 Uniform 变量指定了像素颜色的片元着色器。另外,`lines` Shader 是一个使用 ShaderLab 进行改造的 [shadertoy](https://www.shadertoy.com/view/DtXfDr) 示例。 + + \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/syntax/_meta.json b/docs/zh/graphics/shader/shaderLab/syntax/_meta.json new file mode 100644 index 000000000..73a312cdf --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/_meta.json @@ -0,0 +1,7 @@ +{ + "intro": "总览", + "shader": "Shader", + "subShader": "SubShader", + "pass": "Pass", + "macro": "宏" +} \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/syntax/intro.mdx b/docs/zh/graphics/shader/shaderLab/syntax/intro.mdx new file mode 100644 index 000000000..bfa69c7f8 --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/intro.mdx @@ -0,0 +1,31 @@ +--- +title: ShaderLab 语法标准 +--- + +## 在编辑器中编辑着色器 + +双击我们在上一步创建的着色器资产即可跳转到代码编辑页 + +> 未来版本会推出 Galacean VSCode 插件,该插件会为`ShaderLab`提供语法检测和自动补全功能以及代码同步功能,敬请期待 + + + +## 语法标准 + +`ShaderLab` 语法骨架如下: + +```glsl +Shader "ShaderName" { + ... + SubShader "SubShaderName" { + ... + Pass "PassName" { + ... + } + ... + } + ... +} +``` + +主要包含 [Shader](./shader),[SubShader](./subShader) 和 [ShaderPass](./Pass) 模块。 diff --git a/docs/zh/graphics/shader/shaderLab/syntax/macro.mdx b/docs/zh/graphics/shader/shaderLab/syntax/macro.mdx new file mode 100644 index 000000000..07146a0b2 --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/macro.mdx @@ -0,0 +1,45 @@ +--- +title: 宏 +--- + +ShaderLab 支持 GLSL 标准语法中的部分宏和宏操作符: +- `#define` +- `#undef` +- `#if` +- `#ifdef` +- `#ifndef` +- `#else` +- `#elif` +- `#endif` +- `defined` + +以及额外引入的 `#include` 宏。 + + +ShaderLab 宏会在预处理器阶段被展开,因此宏不能影响 ShaderLab 结构解析,即 `Shader`,`SubShader`,`Pass`,`EditorProperties`,`EditorMacros` 关键字不能被包含在类似 `#ifdef` 这样的分支宏内。 + + +## include 宏 + +为了方便代码段复用,ShaderLab 中可以如下使用 `include` 宏进行代码段引用,后续编译过程中会被自动扩展替换。 + +```glsl +#include "{includeKey}" +``` + +为了能使代码段可以通过 `include` 宏进行引用,我们有 2 种方式进行代码段声明: + +1. 编辑器中创建 着色器 / 着色器片段 + +创建的代码段 `includeKey` 为该文件在工程中的文件路径,比如 `/Root/Effect.glsl` + +2. 脚本中显示注册代码段 + +```ts +import { ShaderFactory } from '@galacean/engine'; + +const commonSource = `// shader chunk`; +ShaderFactory.registerInclude('includeKey', commonSource); +``` + +Shader 文件引入代码段支持相对路径引用,所有相对路径都基于主 Shader 文件路径进行转换。如Shader文件路径为`/root/hair/shader.gs`,引入代码段路径为`/root/hair/common.glsl`,则引入的相对路径为 `#include "./common.glsl"`。 \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/syntax/pass.mdx b/docs/zh/graphics/shader/shaderLab/syntax/pass.mdx new file mode 100644 index 000000000..92a3aa26d --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/pass.mdx @@ -0,0 +1,86 @@ +--- +title: Pass +--- + +```glsl +Pass "PassName" { + Tag {PipelineStage = "ShadowCaster"} + + ... + // 全局变量区:公共变量声明,结构体声明,函数声明 + ... + + // 渲染管线和渲染状态设置 + + // 指定顶点着色器和片元着色器 强调glsl语言 + VertexShader = vert; + + // 指定渲染队列 + RenderQueueType = Transparent; +} +``` + +`Pass` 是 `Shader` 对象的基本元素。简单的着色器对象可能只包含一个 `Pass`,但更复杂的着色器可以包含多个 `Pass`。 它定义了渲染管线特定阶段执行的操作,例如在 GPU 上运行的着色器程序,渲染状态,以及渲染管线相关设置。 + +## 渲染状态 + +可以通过以下两种方式指定 + +1. 显示赋值 + + ``` + BlendState = blendState; + ``` + +2. Pass 全局变量域中声明指定 + + ``` + BlendState blendState { + 渲染状态属性 = 属性值; + } + ``` + +## uniform 变量指定 + +直接声明成全局变量 + +```glsl +mediump vec4 u_color; +float material_AlphaCutoff; +mat4 renderer_ModelMat; +vec3 u_lightDir; +``` + +## varying 变量声明 + +通过定义顶点着色器出参结构体和片元着色器入参结构体指定 + +```glsl +struct v2f { + vec3 color; +} + +v2f vert(a2v o) { + ... +} +void frag(v2f i) { + ... +} +``` + +## 顶点、片元着色器指定 + +通过`VertexShader`和`FragmentShader`指定显示指定着色器入口函数 + +``` +VertexShader = vert; +FragmentShader = frag; +``` + +## 渲染队列设置 + +通过`RenderQueueType`指令指定,`RenderQueueType`等同与引擎 API。 + +``` +RenderQueueType = Transparent; +``` diff --git a/docs/zh/graphics/shader/shaderLab/syntax/shader.mdx b/docs/zh/graphics/shader/shaderLab/syntax/shader.mdx new file mode 100644 index 000000000..fae7f6d7a --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/shader.mdx @@ -0,0 +1,212 @@ +--- +title: Shader +--- + +```glsl +Shader "ShaderName" { + ... + // 全局变量区:变量声明,结构体声明,渲染状态声明,材质属性定义 + ... + SubShader "SubShaderName" { + ... + } + ... +} +``` + +ShaderLab 中的 `Shader` 是传统渲染管线中着色器程序和其他引擎渲染设置相关信息的集合封装,它允许在同一个 `Shader` 对象中定义多个着色器程序,并告诉 Galacean 在渲染过程中如何选择使用它们。`Shader` 对象具有嵌套的结构,包分别对应引擎封装的 [Shader](./class/#shader),[SubShader](./class/#subshader) 和 [ShaderPass](./class/#shaderpass) 对象。 + +## 材质属性定义 + +```glsl +// Uniform +EditorProperties +{ + material_BaseColor("Offset unit scale", Color) = (1,1,1,1); + ... + + Header("Emissive") + { + material_EmissiveColor("Emissive color", Color) = (1,1,1,1); + ... + } + ... +} + +// 宏 +EditorMacros +{ + [On] UV_OFFSET("UV Offset", Range(1,100)) = 10; + ... +} +``` + +此模块用于定义绑定该 Shader 的材质在编辑器 Inspector 面板中的 UI 展示。ShaderLab 材质属性对宏属性和其它 Uniform 属性使用`EditorProperties`和`EditorMacros`进行分开声明,其声明格式为: + +1. Uniform 属性 + + ```glsl + EditorProperties { + propertyName("label in Inspector", type) [= defaultValue]; + ... + [ Header("blockName") { + propertyName("label in Inspector", type) [= defaultValue]; + ... + } ] + } + ``` + + > 可以使用嵌套`Header`块对材质属性进行层级分类。 + + 支持的类型有 + + | Type | Example | + | :-: | :-- | + | Bool | propertyName("Property Description", Boolean) = true; | + | Int | propertyName("Property Description", Int) = 1;
propertyName("Property Description", Range(0,8)) = 1 | + | Float | propertyName("Property Description", FLoat) = 0.5;
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. 宏属性 + + ```glsl + EditorMacros { + [\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue]; + ... + [ Header("blockName") { + [\[Off/On\]] propertyName("label in Inspector"[, type]) [= defaultValue]; + ... + } ] + } + ``` + + 均包含开启和禁用功能,初始化通过 `[On/Off]` 指令指定,其类型包含 + + | Type | Example | + | :-: | :-- | + | 无(开关宏) | macroName("Macro Description"); | + | Bool | macroName("Macro Description", Boolean) = true; | + | Int | macroName("Macro Description", Int) = 1;
macroName("Macro Description", Range(0,8)) = 1; | + | Float | macroName("Macro Description", FLoat) = 0.5;
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); | + +> 注意,当前版本 ShaderLab 材质属性模块只是定义了绑定该 Shader 的材质在编辑器中的 Inspector UI 面板,并不会替你在`ShaderPass`中声明对应的全局变量,如果`ShaderPass`代码中引用了该变量需在全局变量模块(见下文)中明确声明补充。 + +## 全局变量 + +可以在 ShaderLab 中声明 4 类全局变量:渲染状态(RenderState),结构体,函数,以及单变量。 + +- 渲染状态 + + 包含混合状态(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] 可省略,在使用 MRT 的情况下, [n] 为指定某个 MRT 渲染状态,省略为设置所有 MRT 状态,BlendOperation 和 BlendFactor 枚举等同引擎 API + + - DepthState + + ```glsl + DepthState { + Enabled: bool; + WriteEnabled: bool; + CompareFunction: CompareFunction; + } + ``` + + CompareFunction 枚举等同引擎 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 和 StencilOperation 举等同引擎 API + + - RasterState + + ```glsl + RasterState { + CullMode: CullMode; + DepthBias: float; + SlopeScaledDepthBias: float; + } + ``` + + CullMode 举等同引擎 API + + 在`ShaderLab`中设置`BlendState`示例: + + ```glsl + Shader "Demo" { + ... + BlendState customBlendState + { + Enabled = true; + // 常量复制方式 + SourceColorBlendFactor = BlendFactor.SourceColor; + // 变量赋值方式 + DestinationColorBlendFactor = material_DstBlend; + } + ... + Pass "0" { + ... + BlendState = customBlendState; + ... + } + } + ``` + + 上述案例中对于 BlendState 属性赋值展示了 2 种方式: *常量赋值*和*变量赋值*方式: + + - 常量赋值指赋值语句右端为指定的对应引擎枚举变量,譬如:BlendFactor.SourceColor + - 变量赋值指赋值语句右端为任一变量名,变量具体值由用户通过脚本方式在运行时通过 ShaderData.setInt("material_DstBlend", BlendFactor.SourceColor) API 进行指定 + +- 结构体、函数 + + 等同 glsl 中的语法 + +- 单变量 + + ```glsl + [lowp/mediump/highp] variableType variableName; + ``` + +与其他编程语言类似,ShaderLab 中的全局变量也有作用域和同名覆盖原则。简单来说,ShaderLab 中的全局变量的作用范围仅限于其声明的 SubShader 或 Pass 模块内部,而同名覆盖原则指的是如果存在与 Pass 内部同名的全局变量,则 Pass 内的全局变量会覆盖 SubShader 内的同名全局变量。 \ No newline at end of file diff --git a/docs/zh/graphics/shader/shaderLab/syntax/subShader.mdx b/docs/zh/graphics/shader/shaderLab/syntax/subShader.mdx new file mode 100644 index 000000000..34ed18bbb --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/syntax/subShader.mdx @@ -0,0 +1,36 @@ +--- +title: SubShader +--- + +```glsl +SubShader "SubShaderName" { + ... + // 全局变量区:变量声明,结构体声明,渲染状态声明 + ... + Tags {ReplaceTag = "opaque"} + + UsePass "ShaderName/SubShaderName/PassName" + + Pass "PassName" { + ... + } +} +``` + +## Tags + +在 [Shader 对象](./class) 章节我们了解了 Tags 的基本概念和用途,ShaderLab 中可以通过 `Tags` 指令直接声明和指定,无须通过 `SubShader.setTag` api 方式手动指定。 + + +## UsePass + + 如果一个 `SubShader` 包含多个 `Pass`,可以通过 `UsePass` 指令复用其他 `Pass` 对象,比如引擎内置的 PBR Pass: `UsePass "pbr/Default/Forward"` + + | 内置 Shader | Pass 路径 | + | :-------------: | :-----------------------------: | + | PBR | pbr/Default/Forward | + | Unlit | unlit/Default/Forward | + | Skybox | skybox/Default/Forward | + | Particle-shader | particle-shader/Default/Forward | + | SpriteMask | SpriteMask/Default/Forward | + | Sprite | Sprite/Default/Forward | diff --git a/docs/zh/graphics/shader/shaderLab/usage.md b/docs/zh/graphics/shader/shaderLab/usage.md new file mode 100644 index 000000000..a21409b64 --- /dev/null +++ b/docs/zh/graphics/shader/shaderLab/usage.md @@ -0,0 +1,17 @@ +--- +title: "使用" +--- + +有了使用 `ShaderLab` 编写的自定义着色器资产后,我们可以通过将着色器绑定到新建的材质实现用户自定义材质。 + + + +- `ShaderLab`反射材质属性 + +如果我们在 `ShaderLab` 中编写了`材质属性定义`模块,模块中定义的属性会暴露在绑定该 Shader 的材质资产 Inspector 面板中 + + + +## 一个利用多 Pass 技术实现平面阴影的示例 + + diff --git a/examples/shader-lab-multi-pass.ts b/examples/shader-lab-multi-pass.ts index 5b87f6164..28f400bc2 100644 --- a/examples/shader-lab-multi-pass.ts +++ b/examples/shader-lab-multi-pass.ts @@ -18,11 +18,11 @@ import { Texture2D, Vector3, Vector4, - WebGLEngine -} from "@galacean/engine"; -import { ShaderLab } from "@galacean/engine-shader-lab"; -import { OrbitControl } from "@galacean/engine-toolkit-controls"; -import * as dat from "dat.gui"; + WebGLEngine, +} from '@galacean/engine'; +import { ShaderLab } from '@galacean/engine-shader-lab'; +import { OrbitControl } from '@galacean/engine-toolkit-controls'; +import * as dat from 'dat.gui'; const LAYER = 40; @@ -32,7 +32,7 @@ const shaderLab = new ShaderLab(); const loopPassSource = Array.from({ length: LAYER }) .map((_, index) => { const step = (1 / LAYER) * index; - const u_furOffset = step % 1 === 0 ? step + ".0" : step; + const u_furOffset = step % 1 === 0 ? step + '.0' : step; const renderStateSource = index > 0 ? ` @@ -64,7 +64,7 @@ const loopPassSource = Array.from({ length: LAYER }) float mipMapLevel; float diffuseIntensity; float specularIntensity; - } + }; EnvMapLight scene_EnvMapLight; #ifdef SCENE_USE_SH @@ -136,7 +136,7 @@ const loopPassSource = Array.from({ length: LAYER }) } `; }) - .join("\n"); + .join('\n'); const furShaderSource = `Shader "fur-unlit" { SubShader "Default" { @@ -176,12 +176,13 @@ class RandomGravityScript extends Script { shaderData: ShaderData; progress = 0; onUpdate(deltaTime: number) { - const progress = 0.5 + Math.cos((this.progress = this.progress + deltaTime * 2)) / 2; - this.shaderData.setFloat("u_gravityIntensity", progress); + const progress = + 0.5 + Math.cos((this.progress = this.progress + deltaTime * 2)) / 2; + this.shaderData.setFloat('u_gravityIntensity', progress); } } -WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { +WebGLEngine.create({ canvas: 'canvas', shaderLab }).then((engine) => { engine.canvas.resizeByClientSize(); const furShader = Shader.create(furShaderSource); @@ -189,7 +190,7 @@ WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { const rootEntity = scene.createRootEntity(); // camera - const cameraEntity = rootEntity.createChild("cameraNode"); + const cameraEntity = rootEntity.createChild('cameraNode'); cameraEntity.transform.setPosition(0, 0, 5); cameraEntity.addComponent(Camera); cameraEntity.addComponent(OrbitControl); @@ -198,16 +199,16 @@ WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { .load([ { type: AssetType.Texture2D, - url: "https://mdn.alipayobjects.com/huamei_dmxymu/afts/img/A*R75iTZlbVfgAAAAAAAAAAAAADuuHAQ/original" + url: 'https://mdn.alipayobjects.com/huamei_dmxymu/afts/img/A*R75iTZlbVfgAAAAAAAAAAAAADuuHAQ/original', }, { type: AssetType.Texture2D, - url: "https://mdn.alipayobjects.com/huamei_dmxymu/afts/img/A*t1s4T7h_1OQAAAAAAAAAAAAADuuHAQ/original" + url: 'https://mdn.alipayobjects.com/huamei_dmxymu/afts/img/A*t1s4T7h_1OQAAAAAAAAAAAAADuuHAQ/original', }, { type: AssetType.Env, - url: "https://gw.alipayobjects.com/os/bmw-prod/6470ea5e-094b-4a77-a05f-4945bf81e318.bin" - } + url: 'https://gw.alipayobjects.com/os/bmw-prod/6470ea5e-094b-4a77-a05f-4945bf81e318.bin', + }, ]) .then((res) => { const layerTexture = res[0] as Texture2D; @@ -215,7 +216,7 @@ WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { scene.ambientLight = res[2] as AmbientLight; // create sphere - const entity = rootEntity.createChild("sphere"); + const entity = rootEntity.createChild('sphere'); const renderer = entity.addComponent(MeshRenderer); renderer.mesh = PrimitiveMesh.createSphere(engine, 0.5, 16); @@ -224,13 +225,13 @@ WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { const shaderData = material.shaderData; - shaderData.setTexture("u_mainTex", baseTexture); - shaderData.setTexture("u_layerTex", layerTexture); + shaderData.setTexture('u_mainTex', baseTexture); + shaderData.setTexture('u_layerTex', layerTexture); - shaderData.setFloat("u_furLength", 0.5); - shaderData.setVector4("u_uvTilingOffset", new Vector4(5, 5, 0.5, 0.5)); - shaderData.setVector3("u_gravity", new Vector3(0, 0, 0)); - shaderData.setFloat("u_gravityIntensity", 0); + shaderData.setFloat('u_furLength', 0.5); + shaderData.setVector4('u_uvTilingOffset', new Vector4(5, 5, 0.5, 0.5)); + shaderData.setVector3('u_gravity', new Vector3(0, 0, 0)); + shaderData.setFloat('u_gravityIntensity', 0); const randomGravityScript = entity.addComponent(RandomGravityScript); randomGravityScript.shaderData = shaderData; @@ -241,25 +242,25 @@ WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => { uvOffset: 0.5, enable: () => { randomGravityScript.enabled = !randomGravityScript.enabled; - shaderData.setFloat("u_gravityIntensity", 0); + shaderData.setFloat('u_gravityIntensity', 0); randomGravityScript.progress = 0; - } + }, }; - gui.add(debugInfo, "u_furLength", 0, 1, 0.01).onChange((v) => { - shaderData.setFloat("u_furLength", v); + gui.add(debugInfo, 'u_furLength', 0, 1, 0.01).onChange((v) => { + shaderData.setFloat('u_furLength', v); }); - gui.add(debugInfo, "uvScale", 1, 20, 1).onChange((v) => { - const value = shaderData.getVector4("u_uvTilingOffset"); + gui.add(debugInfo, 'uvScale', 1, 20, 1).onChange((v) => { + const value = shaderData.getVector4('u_uvTilingOffset'); value.x = value.y = v; }); - gui.add(debugInfo, "uvOffset", -1, 1, 0.01).onChange((v) => { - const value = shaderData.getVector4("u_uvTilingOffset"); + gui.add(debugInfo, 'uvOffset', -1, 1, 0.01).onChange((v) => { + const value = shaderData.getVector4('u_uvTilingOffset'); value.z = value.w = v; }); - gui.add(scene.ambientLight, "diffuseIntensity", 0, 1, 0.01); - gui.add(debugInfo, "enable").name("pause/resume"); + gui.add(scene.ambientLight, 'diffuseIntensity', 0, 1, 0.01); + gui.add(debugInfo, 'enable').name('pause/resume'); engine.run(); }); }); diff --git a/examples/shader-lab-simple.ts b/examples/shader-lab-simple.ts index 2ddc5b7f8..29bd452cb 100644 --- a/examples/shader-lab-simple.ts +++ b/examples/shader-lab-simple.ts @@ -33,11 +33,11 @@ const normalShaderSource = `Shader "Triangle" { struct a2v { vec4 POSITION; - } + }; struct v2f { vec3 v_color; - } + }; VertexShader = vert; FragmentShader = frag; @@ -66,12 +66,12 @@ Shader "Lines" { struct a2v { vec4 POSITION; - } + }; struct v2f { vec4 v_pos; vec3 v_color; - } + }; VertexShader = vert; FragmentShader = frag; @@ -94,10 +94,9 @@ Shader "Lines" { } void frag(v2f i) { - vec2 iResolution = vec2(1.0, 1.0); - vec2 uv = i.v_pos.xy / iResolution.y; + vec2 uv = i.v_pos.xy; vec4 color = vec4(0.0); - for (float i = 0.0; i <= 7.0; i += 1.0) { + for (float i = 0.0; i <= 5.; i += 1.0) { float t = i / 5.0; color += Line(uv, 1.0 + t, 4.0 + t, vec3(0.2 + t * 0.7, 0.2 + t * 0.4, 0.3)); } diff --git a/examples/shader-lab.ts b/examples/shader-lab.ts index 0bfb8035b..8b62dcf7a 100644 --- a/examples/shader-lab.ts +++ b/examples/shader-lab.ts @@ -138,7 +138,7 @@ const PlanarShadowShaderSource = `Shader "PlanarShadow" { BlendState = blendState; - RenderQueueType = RenderQueueType.Transparent; + RenderQueueType = Transparent; vec3 u_lightDir; float u_planarHeight; @@ -189,11 +189,11 @@ const PlanarShadowShaderSource = `Shader "PlanarShadow" { vec4 POSITION; vec4 JOINTS_0; vec4 WEIGHTS_0; - } + }; struct v2f { vec4 color; - } + }; v2f vert(a2v v) { v2f o; diff --git a/examples/shader-water.ts b/examples/shader-water.ts index 3b0457189..46889cb47 100644 --- a/examples/shader-water.ts +++ b/examples/shader-water.ts @@ -36,13 +36,13 @@ const shaderSource = `Shader "customWater" { vec3 POSITION; vec2 TEXCOORD_0; vec3 NORMAL; - } + }; struct v2f { vec2 v_uv; vec3 v_position; vec3 v_normal; - } + }; v2f vert(a2v v) { v2f o;