[Document] enhance material document (#2546)

* doc: enhance material document
This commit is contained in:
zhuxudong
2025-03-31 15:45:10 +08:00
committed by GitHub
parent c5c86e9fc4
commit 3242f8941f
33 changed files with 579 additions and 275 deletions

View File

@@ -20,9 +20,6 @@
"material": {
"title": "材质"
},
"shader": {
"title": "着色器"
},
"texture": {
"title": "纹理"
},

View File

@@ -1,6 +1,7 @@
{
"material": { "title": "材质总览" },
"composition": { "title": "材质组成" },
"editor": { "title": "编辑器使用" },
"script": { "title": "脚本使用" }
"overview": { "title": "材质概述" },
"examples": { "title": "指南和示例" },
"builtinShaders": { "title": "内置着色器" },
"shaderLab": { "title": "ShaderLab 语法" },
"variables": "内置变量"
}

View File

@@ -1,7 +1,6 @@
{
"intro": {"title": "介绍"},
"pbr": "PBR",
"unlit": "Unlit",
"blinnPhong": "Blinn Phong",
"digitalHuman": "数字人"
}
}

View File

@@ -0,0 +1,28 @@
---
title: Blinn Phong
---
[BlinnPhongMaterial](/apis/core/#BlinnPhongMaterial) 材质是经典的材质之一,虽然不是基于物理渲染,但是其高效的渲染算法和基本齐全的光学部分,流传至今仍可以适用很多的场景。
<playground src="blinn-phong.ts"></playground>
## 编辑器使用
<img src="https://gw.alipayobjects.com/zos/OasisHub/eaa93827-29a4-46ad-b9d3-f179fa200c57/blinn.gif" alt="blinn" style="zoom:100%;" />
## 参数介绍
| 参数 | 应用 |
| :-- | :-- |
| [baseColor](/apis/core/#BlinnPhongMaterial-baseColor) | 基础颜色。 **基础颜色 \* 基础纹理 = 最后的基础颜色。** |
| [baseTexture](/apis/core/#BlinnPhongMaterial-baseTexture) | 基础纹理。搭配基础颜色使用,是个相乘的关系。 |
| [specularColor](/apis/core/#BlinnPhongMaterial-specularColor) | 镜面反射颜色。**镜面反射颜色 \* 镜面反射纹理 = 最后的镜面反射颜色。** |
| [specularTexture](/apis/core/#BlinnPhongMaterial-specularTexture) | 镜面反射纹理。搭配镜面反射颜色使用,是个相乘的关系。 |
| [normalTexture](/apis/core/#BlinnPhongMaterial-normalTexture) | 法线纹理。可以设置法线纹理 ,在视觉上造成一种凹凸感,还可以通过法线强度来控制凹凸程度。 |
| [normalIntensity ](/apis/core/#BlinnPhongMaterial-normalIntensity) | 法线强度。法线强度,用来控制凹凸程度。 |
| [emissiveColor](/apis/core/#BlinnPhongMaterial-emissiveColor) | 自发光颜色。**自发光颜色 \* 自发光纹理 = 最后的自发光颜色。即使没有光照也能渲染出颜色。** |
| [emissiveTexture](/apis/core/#BlinnPhongMaterial-emissiveTexture) | 自发光纹理。搭配自发光颜色使用,是个相乘的关系。 |
| [shininess](/apis/core/#BlinnPhongMaterial-shininess) | 镜面反射系数。值越大镜面反射效果越聚拢。 |
| [tilingOffset](/apis/core/#BlinnPhongMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](/embed/tiling-offset) |
如果需要通过脚本使用材质,可以前往[材质的使用教程](/docs/graphics/material/examples/create/#3-脚本方式)。

View File

@@ -0,0 +1,65 @@
---
title: Unlit
---
在一些简单的场景中,可能不希望计算光照,引擎提供了 [UnlitMaterial](/apis/core/#UnlitMaterial),使用了最精简的 shader 代码只需要提供颜色或者纹理即可渲染。Unlit 材质适用于烘焙好的模型渲染,它只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响。
<playground src="unlit-material.ts"></playground>
## 编辑器使用
<img src="https://gw.alipayobjects.com/zos/OasisHub/6be78a08-3075-4cd1-8cad-9757fc34f695/unlit.gif" alt="unlit" style="zoom:100%;" />
## 参数介绍
| 参数 | 应用 |
| :-- | :-- |
| [baseColor](/apis/core/#UnlitMaterial-baseColor) | 基础颜色。**基础颜色 \* 基础颜色纹理 = 最后的颜色。** |
| [baseTexture](/apis/core/#UnlitMaterial-baseTexture) | 基础纹理。搭配基础颜色使用,是个相乘的关系。 |
| [tilingOffset](/apis/core/#UnlitMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](/embed/tiling-offset) |
如果需要通过脚本使用材质,可以前往[材质的使用教程](/docs/graphics/material/script)。
## Blender 导出 Unlit 材质
如[烘焙教程](/docs/art/bake-blender)介绍,如果我们已经制作完了烘焙贴图,希望有一种**便捷材质**,颜色只由烘焙纹理影响,不用添加灯光,不用调试法线,也不用调试金属粗糙度等高阶属性,那么你可以试试 Galacean 的 [UnlitMaterial](/apis/core/#UnlitMaterial), glTF 有专门的[KHR_materials_unlit ](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit)插件Galacean 会解析插件,生成 Unlit 材质。
<img src="https://gw.alipayobjects.com/zos/OasisHub/39965fc2-3fc2-44b9-a294-a04eb4441120/1623652741734-090284d5-9b1a-4db8-9231-dc3f4d188a38-20210614150743080.png" alt="image.png" style="zoom:50%;" />
测试模型:[TREX.zip](https://www.yuque.com/attachments/yuque/0/2021/zip/381718/1623651429048-7f6a3610-d5cb-4a73-97f5-0d37d0c63b2c.zip?_lake_card=%7B%22src%22%3A%22https%3A%2F%2Fwww.yuque.com%2Fattachments%2Fyuque%2F0%2F2021%2Fzip%2F381718%2F1623651429048-7f6a3610-d5cb-4a73-97f5-0d37d0c63b2c.zip%22%2C%22name%22%3A%22TREX.zip%22%2C%22size%22%3A499161%2C%22type%22%3A%22application%2Fx-zip-compressed%22%2C%22ext%22%3A%22zip%22%2C%22status%22%3A%22done%22%2C%22taskId%22%3A%22u458bcbec-d647-4328-8036-3d5eb12860f%22%2C%22taskType%22%3A%22upload%22%2C%22id%22%3A%22ua8a5baad%22%2C%22card%22%3A%22file%22%7D)
接下来介绍如何利用 Blender 软件导出有 unlit 插件的 glTF 文件 。
1. 导入模型
![image.png](https://gw.alipayobjects.com/zos/OasisHub/e5dbfb61-5c0c-4ca5-8c7f-bde353d4c211/1623651809057-138f49cf-6fe7-4f54-8161-c7e157ec85fd-20210614150752343.png)
2. 修改 Shader
默认的 shader 类型为 BSDF ,我们需要将材质属性栏 surface 里面的 shader 类型修改为 **Background**
![image.png](https://gw.alipayobjects.com/zos/OasisHub/abf1e279-1f78-4d21-8c1f-d58d7f74992c/1623652169374-7f39e5f0-6639-4795-8565-b8f0b09420ed-20210614150804567.png)
![image.png](https://gw.alipayobjects.com/zos/OasisHub/c8c51e5f-c7c6-44a3-87e2-dc649e13fddb/1623652230768-69cd6f7e-175d-4f9f-9042-b3629d422b8e.png)
3. 添加烘焙纹理
添加烘焙好的纹理,将 Color 和 Shader 连接在一起
![image.png](https://gw.alipayobjects.com/zos/OasisHub/50c69e7b-c099-4a2d-b546-8a55ff4f9309/1623652264008-7ae4c13c-6430-44b0-995e-2c23c9f117a7-20210614150846797.png)
![image.png](https://gw.alipayobjects.com/zos/OasisHub/6ed13e19-a9e5-4454-a0d5-ad27b3cabe14/1623652368637-6dda44be-4cde-4f65-a72f-d39b5d3f60ce.png)
![image.png](https://gw.alipayobjects.com/zos/OasisHub/e9a99c9c-f661-4666-86bc-d8e91030c0f7/1623652380351-501dd929-7f96-4578-b49a-11724a0782a7.png)
4. 导出 glTF
若预览正常,导出 glTF 。
![image.png](https://gw.alipayobjects.com/zos/OasisHub/4b6b5f8f-ebd2-46af-85c7-9a26b5f66a2e/1623652403568-450291a8-1a0b-4cf4-8e71-c183a05632b0-20210614150902221.png)
![image.png](https://gw.alipayobjects.com/zos/OasisHub/1fe38185-399e-4f56-bff4-c39ba4ae3a2a/1623652462007-85b065a3-69fa-4d80-9dfd-834ef66da12a.png)
将刚才导出来的 glTF 文件拖入编辑器或者 [glTF 预览器](https://galacean.antgroup.com/engine/gltf-viewer),若材质类型为 **UnlitMaterial**,说明已经导出了 glTF 的 [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit) 插件,且 Galacean 已经解析成 Unlit 材质。
![image.png](https://gw.alipayobjects.com/zos/OasisHub/fbb6ba43-f7d7-4757-a1d3-590083d30573/1623652636074-d8bb8437-f885-43fd-8957-8e14ae9fd8c0-20210614150914493.png)

View File

@@ -0,0 +1,6 @@
{
"create": { "title": "创建材质" },
"builtin": { "title": "使用内置着色器" },
"custom": { "title": "自定义着色器" },
"shaderData": { "title": "使用着色器数据" }
}

View File

@@ -0,0 +1,30 @@
---
title: 使用内置着色器
---
目前 Galacean 引擎内置了许多常用的 Shader诸如
| 类型 | 描述 |
| :-- | :-- |
| [Unlit](/docs/graphics/material/builtinShaders/unlit) | Unlit Shader 适用于烘焙好的模型渲染,她只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响,可参考 [烘焙教程](/docs/art/bake-blender) 和 [导出 Unlit 教程](/docs/graphics/shader/builtins/unlit) |
| [Blinn Phong](/docs/graphics/material/builtinShaders/blinnPhong/) | Blinn Phong Shader 适用于那些对真实感没有那么高要求的场景,虽然没有遵循物理,但是其高效的渲染算法和基本齐全的光学部分,可以适用很多的场景。 |
| [PBR](/docs/graphics/material/builtinShaders/pbr) | PBR Shader 适合需要真实感渲染的应用场景,因为 PBR 是基于物理的渲染,遵循能量守恒,开发者通过调整金属度、粗糙度、灯光等参数,能够保证渲染效果都是物理正确的。 |
| [头发](/docs/graphics/material/builtinShaders/digitalHuman/hair) | 头发着色基于着色模型 kajiya-Kay ,近似的模拟了发丝表面双层各向异性高光,在头发渲染中俗称“天使环”。 |
| [皮肤](/docs/graphics/material/builtinShaders/digitalHuman/skin) | 皮肤采用 Spherical Gaussial 模型,可以灵活的自定义不同的 Diffusion Profile (扩散剖面),模拟人类皮肤或者普通的次表面散射效果。 |
| [眼睛](/docs/graphics/material/builtinShaders/digitalHuman/eye) | 眼睛着色器为眼球模型提供真实的渲染,使你的创作呈现逼真的艺术效果。 |
可以在编辑器中直接调试内置着色器的对应属性观察实时渲染效果变化。
<Image src="https://gw.alipayobjects.com/zos/OasisHub/cd87c11a-7a68-4cde-a19a-40cff943e878/2025-02-10%25252017.05.33.gif" />
内置 Shader 基本上都有以下通用参数:
| 参数 | 应用 |
| :-- | :-- |
| [isTransparent](/apis/core/#BaseMaterial-isTransparent) | 是否透明。可以设置材质是否透明。如果设置为透明,可以通过 [BlendMode](/apis/core/#BaseMaterial-blendMode) 来设置颜色混合模式。 |
| [alphaCutoff](/apis/core/#BaseMaterial-alphaCutoff) | 透明度裁剪值。可以设置裁剪值,在着色器中,透明度小于此数值的片元将会被裁减,参考 [案例](/embed/blend-mode) |
| [renderFace](/apis/core/#BaseMaterial-renderFace) | 渲染面。可以决定渲染正面、背面、双面。 |
| [blendMode](/apis/core/#BaseMaterial-blendMode) | 颜色混合模式。当设置材质为透明后,可以设置此枚举来决定颜色混合模式,参考 [案例](/embed/blend-mode) |
| [tilingOffset](/apis/core/#BaseMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](/embed/tiling-offset) |
每个 Shader 有不同的渲染效果和应用场景,更多详情参考 [内置着色器教程](/docs/graphics/material/builtinShaders/pbr/)。

View File

@@ -0,0 +1,48 @@
---
title: 创建材质
---
创建材质一般有以下 3 种方式:
## 1. 手动创建
<Image src="https://gw.alipayobjects.com/zos/OasisHub/b01b0ee2-317e-4acb-8c2f-e07736179d67/image-20240206163405147.png" />
## 2. 模型中的材质
参考[模型的导入和使用](/docs/graphics/model/use/)教程,我们可以先将模型导入到编辑器,一般情况下,模型已经自动绑定好材质,用户可以不用做任何操作;
### 2.1. Remap 材质
如果想要修改模型材质,我们可以点击 `duplicate and remap` 按钮来生成一份该材质的副本,注意 Remap 会修改模型预设,如下图所有模型实例都会受到影响:
<Image src="https://gw.alipayobjects.com/zos/OasisHub/4a41f66e-5523-43f0-a9b5-4028b9d14cbc/2025-01-24%25252015.30.31.gif" />
### 2.2. 增量修改
如果只想修改某个模型的材质,可以使用增量修改的功能:
<Image src="https://gw.alipayobjects.com/zos/OasisHub/5d2409f2-a7b2-4b5e-9e6a-9845c3358af3/2025-01-24%25252015.32.04.gif" />
## 3. 脚本方式
我们还可以通过脚本来创建/修改材质,我们将脚本挂载到立方体实体上,实现替换材质的一个 Demo
```ts showLineNumbers
export default class extends Script {
onStart() {
// 获取所有 renderer
const renderers = [];
this.entity.getComponentsIncludeChildren(MeshRenderer, renderers);
const renderer = renderers[0];
// 直接修改材质
const material = renderer.getMaterial();
material.baseColor.set(1, 0, 0, 1);
// 或者替换材质
const pbrMaterial = new PBRMaterial(engine);
const material = renderer.setMaterial(material);
}
}
```

View File

@@ -1,13 +1,8 @@
---
title: Shader API【实验】
title: 自定义着色器
---
<Callout type="warning">
目前这个版本还处于实验性质,仅可在`编辑器`中使用。如果您想在 `Pro Code` 中使用,需要引入
`@galacean/engine-shader-shaderlab` 包。请注意,下个版本的 API 可能会发生变更,届时我们会及时通知您。
</Callout>
类似于 Typescript 中的函数、类、属性, Shader 代码也有一套自己的 API。本文可以帮助你如何基于这些 API 和 `ShaderLab` 语法,编写自己的 Shader。
类似于 Typescript 中的函数、类、属性, Shader 代码也有一套自己的 API 和配套的 [UIScript](/docs/graphics/material/shaderLab/editor/#uiscript)。本文可以帮助你如何基于这些 API 和 [ShaderLab](/docs/graphics/material/shaderLab/intro) 语法,自定义自己的 Shader。
## 快速上手
@@ -18,6 +13,13 @@ title: Shader API【实验】
style={{ zoom: "50%" }}
/>
引擎会自动帮我们创建好 Shader 文件和 [UIScript](/docs/graphics/material/shaderLab/editor/#uiscript) 文件
<img
src="https://gw.alipayobjects.com/zos/OasisHub/6351fa81-5159-4469-bd95-8f21a8f2f4ac/image-20250124162909194.png"
style={{ zoom: "50%" }}
/>
默认的 Unlit 模板已经内置了蒙皮计算和 Shadow Pass可以看到骨骼动画和阴影都能正常渲染
<Image src="https://gw.alipayobjects.com/zos/OasisHub/6e7f7d40-e54c-45bc-a915-dfbfb26c2c74/2024-08-01%25252017.01.06.gif" />
@@ -160,7 +162,7 @@ vec4 fog(vec4 color, vec3 positionVS);
### Transform
提供了模型空间、视图空间、世界空间、相机坐标等[系统变量](/docs/graphics/shader/custom/#属性):
提供了模型空间、视图空间、世界空间、相机坐标等[系统变量](/docs/graphics/material/variables/):
```glsl
mat4 renderer_LocalMat;
@@ -243,9 +245,7 @@ void calculateBlendShape(Attributes attributes, inout vec4 position, inout vec3
## PBR API
除了通用 APIPBR 也封装了一些列如 BRDF 光照模型的 API这是 `ForwardPassPBR` 的一些核心链路,用户拓展别的材质,比如 SSS薄膜干涉等时候有时候也需要这些功能可以尝试 `#include` 复用这些 API。
<Image src="https://gw.alipayobjects.com/zos/OasisHub/dd9af974-f4d2-4ef5-845a-732f39492bc0/yuque_diagram.jpg" />
除了通用 APIPBR 也封装了一些列如 `BRDF` 光照模型的 API用户拓展别的材质时可以尝试 `#include` 复用这些 API。
### AttributesPBR

View File

@@ -0,0 +1,104 @@
---
title: 使用着色器数据
---
跟别的编程语言一样,我们在写着色器过程中也会用到很多变量,首先引擎有很多 [内置变量](/docs/graphics/material/variables),这部分的变量我们是不需要手动设置的,可以直接在 shader 中使用。接下来我们看看如何设置和使用自定义数据。
### 设置数据
我们推荐使用 [ShaderLab](/docs/graphics/material/shaderLab/intro) 语法来声明和使用着色器数据:
```glsl showLineNumbers {3,8,17,21}
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("Common") {
SOME_MACRO("label", Int) = 1;
}
}
...
// 指定 Shader 绑定的 UIScript 编辑器项目路径。
UIScript "./shaderScript.ts";
}
```
<Callout type="positive">
参考 [ShaderLab 语法](/docs/graphics/material/shaderLab/editor/#properties-属性) 使用更多类型的数据。
</Callout>
当然,我们也可以通过代码设置着色器数据:
```ts showLineNumbers
// shaderData 可以分别保存在 scene 、camera 、renderer、 material 中。
const shaderData = material.shaderData;
// 上传不同类型的着色器数据
shaderData.setFloat("u_float", 1.5);
shaderData.setInt("u_int", 1);
shaderData.setInt("u_bool", 1);
shaderData.setVector2("u_vec2", new Vector2(1, 1));
shaderData.setVector3("u_vec3", new Vector3(1, 1, 1));
shaderData.setVector4("u_vec4", new Vector4(1, 1, 1, 1));
shaderData.setMatrix("u_matrix", new Matrix());
shaderData.setIntArray("u_intArray", new Int32Array(10));
shaderData.setFloatArray("u_floatArray", new Float32Array(10));
shaderData.setTexture("u_sampler2D", texture2D);
shaderData.setTexture("u_samplerCube", textureCube);
shaderData.setTextureArray("u_samplerArray", [texture2D, textureCube]);
// 开启宏开关
shaderData.enableMacro("DISCARD");
// 关闭宏开关
shaderData.disableMacro("DISCARD");
// 开启变量宏
shaderData.enableMacro("LIGHT_COUNT", "3");
// 切换变量宏。这里底层会自动 disable 上一个宏,即 “LIGHT_COUNT 3”
shaderData.enableMacro("LIGHT_COUNT", "2");
// 关闭变量宏
shaderData.disableMacro("LIGHT_COUNT");
```
### 获取数据
当你设置完数据后,你已经可以在 Shader 中直接使用,如下:
```glsl showLineNumbers filename="test.glsl"
float test = u_float;
int test = u_int;
bool test = u_bool;
vec2 test = u_vec2;
mat4 test = u_matrix;
sampler2D test = u_sampler2D;
...
```
你也可以通过代码获取这个变量的值:
```ts showLineNumbers filename="test.ts"
const test = shaderData.getFloat("u_float");
const test = shaderData.getInt("u_int");
const test = shaderData.getVector2("u_vec2");
const test = shaderData.getMatrix("u_matrix");
const test = shaderData.getTexture("u_sampler2D");
```

View File

@@ -0,0 +1,44 @@
---
title: 材质概述
---
<Image src="https://mdn.alipayobjects.com/huamei_9ahbho/afts/img/A*Iq8iRKWPAqgAAAAAAAAAAAAADgDwAQ/original" />
材质包含 **着色器shader、着色器数据shaderData、渲染状态renderStates**。
## 着色器
着色器(Shader)是一段运行在GPU中的程序通常由顶点着色器和片元着色器组成我们可以借助 [ShaderLab 语法](/docs/graphics/material/shaderLab/intro/) 很方便地书写这部分代码。
## 着色器数据
跟别的编程语言一样,我们在写着色器过程中也会用到很多变量,我们可以参考 [内置变量文档](/docs/graphics/material/variables/) 查找想要的内置变量;也可以通过 [使用着色器数据教程](/docs/graphics/material/examples/shaderData) 手动上传着色器数据和宏开关:
## 渲染状态
Galacean 支持对[混合状态BlendState](/apis/core/#RenderState-BlendState)、[深度状态DepthState](/apis/core/#RenderState-DepthState)、[模版状态StencilState](/apis/core/#RenderState-StencilState)、[光栅状态RasterState](/apis/core/#RenderState-RasterState)进行配置。
我们拿一个透明物体的标准渲染流程来举例,我们希望开启透明混合,并且因为透明物体是叠加渲染的,所以我们还要关闭深度写入,并设置为透明队列;
```ts showLineNumbers {3,7-12,14}
Pass "Pass0" {
DepthState {
WriteEnabled = false;
}
BlendState {
Enabled = true;
SourceColorBlendFactor = BlendFactor.SourceAlpha;
DestinationColorBlendFactor = BlendFactor.OneMinusSourceAlpha;
SourceAlphaBlendFactor = BlendFactor.One;
DestinationAlphaBlendFactor = BlendFactor.OneMinusSourceAlpha;
}
RenderQueueType = Transparent;
}
```
<Callout type="info">
渲染状态还可以设置为变量,然后通过着色器数据来控制,详情参考 [ShaderLab
文档](/docs/graphics/material/shaderLab/shader)。
</Callout>

View File

@@ -0,0 +1,135 @@
---
title: ShaderLab 语法标准
---
## 语法标准
`ShaderLab` 语法骨架如下:
```glsl
Shader "ShaderName" {
...
Editor {
...
}
...
SubShader "SubShaderName" {
...
Pass "PassName" {
...
}
...
}
...
}
```
## Unlit Demo
```ts showLineNumbers {2,18,21}
Shader "ShaderName" {
Editor {
Properties {
material_BaseColor("Main Color", Color) = (0, 0, 0, 1);
material_BaseTexture("Texture", Texture2D);
material_AlphaCutoff("Alpha Cutoff", Range(0, 1, 0.01)) = 0;
Header("Common"){
isTransparent("Transparent", Boolean) = false;
renderFace("Render Face", Enum(Front:0, Back:1, Double:2)) = 0;
blendMode("Blend Mode", Enum(Normal:0, Additive:1)) = 0;
}
}
UIScript "${uiScriptPath}";
}
SubShader "Default" {
UsePass "pbr/Default/ShadowCaster"
Pass "Pass0" {
DepthState {
WriteEnabled = depthWriteEnabled;
}
BlendState {
Enabled = blendEnabled;
SourceColorBlendFactor = sourceColorBlendFactor;
DestinationColorBlendFactor = destinationColorBlendFactor;
SourceAlphaBlendFactor = sourceAlphaBlendFactor;
DestinationAlphaBlendFactor = destinationAlphaBlendFactor;
}
RasterState{
CullMode = rasterStateCullMode;
}
RenderQueueType = renderQueueType;
struct Attributes {
vec3 POSITION;
vec2 TEXCOORD_0;
vec4 JOINTS_0;
vec4 WEIGHTS_0;
};
struct Varyings {
vec2 uv;
};
#include "Common.glsl"
#include "Skin.glsl"
#include "Transform.glsl"
vec4 material_BaseColor;
float material_AlphaCutoff;
sampler2D material_BaseTexture;
VertexShader = vert;
FragmentShader = frag;
Varyings vert(Attributes attr) {
Varyings v;
vec4 position = vec4(attr.POSITION, 1.0);
// Skin
#ifdef RENDERER_HAS_SKIN
mat4 skinMatrix = getSkinMatrix(attr);
position = skinMatrix * position;
#endif
gl_Position = renderer_MVPMat * position;
v.uv = attr.TEXCOORD_0;
return v;
}
void frag(Varyings v) {
vec4 baseColor = material_BaseColor;
#ifdef MATERIAL_HAS_BASETEXTURE
vec4 textureColor = texture2D(material_BaseTexture, v.uv);
#ifndef ENGINE_IS_COLORSPACE_GAMMA
textureColor = gammaToLinear(textureColor);
#endif
baseColor *= textureColor;
#endif
#ifdef MATERIAL_IS_ALPHA_CUTOFF
if( baseColor.a < material_AlphaCutoff ) {
discard;
}
#endif
gl_FragColor = baseColor;
#ifndef ENGINE_IS_COLORSPACE_GAMMA
gl_FragColor = linearToGamma(gl_FragColor);
#endif
}
}
}
}
```

View File

@@ -53,7 +53,7 @@ vec3 u_lightDir;
## varying 变量声明
通过定义顶点着色器出参[结构体](/docs/graphics/shader/shaderLab/syntax/shader/#结构体函数)和片元着色器入参结构体指定
通过定义顶点着色器出参[结构体](/docs/graphics/material/shaderLab/shader/#结构体函数)和片元着色器入参结构体指定
```glsl
struct v2f {

View File

@@ -0,0 +1,35 @@
---
title: SubShader
---
```glsl
SubShader "SubShaderName" {
...
// 全局变量区:变量声明,结构体声明,渲染状态声明
...
Tags {ReplaceTag = "opaque"}
UsePass "ShaderName/SubShaderName/PassName"
Pass "PassName" {
...
}
}
```
## 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 |

View File

@@ -0,0 +1,60 @@
---
title: 内置变量
---
Shader 代码中会经常用到内置变量,一种是**逐顶点**的 `attribute` 变量,另一种是**逐 shader** 的 `uniform` 变量。
下面是引擎内置变量,可以在写 Shader 的时候进行参考:
### 顶点输入
| 逐顶点数据 | attribute name | 数据类型 |
| :------------- | :------------- | :------- |
| 顶点 | POSITION | vec3 |
| 法线 | NORMAL | vec3 |
| 切线 | TANGENT | vec4 |
| 顶点颜色 | COLOR_0 | vec4 |
| 骨骼索引 | JOINTS_0 | vec4 |
| 骨骼权重 | WEIGHTS_0 | vec4 |
| 第一套纹理坐标 | TEXCOORD_0 | vec2 |
| 第二套纹理坐标 | TEXCOORD_1 | vec2 |
### 属性
#### 渲染器
| 名字 | 类型 | 解释 |
| :----------------- | :--- | ------------------ |
| renderer_LocalMat | mat4 | 模型本地坐标系矩阵 |
| renderer_ModelMat | mat4 | 模型世界坐标系矩阵 |
| renderer_MVMat | mat4 | 模型视口矩阵 |
| renderer_MVPMat | mat4 | 模型视口投影矩阵 |
| renderer_NormalMat | mat4 | 法线矩阵 |
#### 相机
| 名字 | 类型 | 解释 |
| :----------------------- | :-------- | --------------------------------------------------------------------- |
| camera_ViewMat | mat4 | 视口矩阵 |
| camera_ProjMat | mat4 | 投影矩阵 |
| camera_VPMat | mat4 | 视口投影矩阵 |
| camera_ViewInvMat | mat4 | 视口逆矩阵 |
| camera_Position | vec3 | 相机位置 |
| camera_DepthTexture | sampler2D | 深度信息纹理 |
| camera_OpaqueTexture | sampler2D | 非透明纹理 |
| camera_DepthBufferParams | Vec4 | 相机深度缓冲参数:(x: 1.0 - far / near, y: far / near, z: 0, w: 0) |
| camera_ProjectionParams | Vec4 | 投影矩阵相关参数:(x: flipProjection ? -1 : 1, y: near, z: far, w: 0) |
#### 时间
| 名字 | 类型 | 解释 |
| :---------------- | :--- | :-------------------------------------------------------- |
| scene_ElapsedTime | vec4 | 引擎启动后经过的总时间:(x: t, y: sin(t), z:cos(t), w: 0) |
| scene_DeltaTime | vec4 | 距离上一帧的间隔时间:(x: dt, y: 0, z:0, w: 0) |
#### 雾
| 名字 | 类型 | 解释 |
| :-- | :-- | :-- |
| scene_FogColor | vec4 | 雾的颜色 |
| scene_FogParams | vec4 | 雾的参数:(x: -1/(end-start), y: end/(end-start), z: density / ln(2), w: density / sqr(ln(2)) |

View File

@@ -81,13 +81,18 @@ const customShader = Shader.create(
我们新建一个 Pass在 [onRender 钩子](/apis/core/#PostProcessUberPass-onRender) 里面直接 [Blitter](/apis/core/#Blitter) 到屏幕,然后将这个 Pass 添加到引擎中。
```ts showLineNumbers {10,15} filename="CustomPostProcessPass.ts"
```ts showLineNumbers {15,20} filename="CustomPostProcessPass.ts"
class CustomPass extends PostProcessPass {
private _blitMaterial: Material;
constructor(engine: Engine) {
super(engine);
this._blitMaterial = new Material(this.engine, customShader);
// 我们这里关掉深度测试和深度写入,保证每次 Blit 都能覆盖到屏幕上。
const depthState = this._blitMaterial.renderState.depthState;
depthState.enabled = false;
depthState.writeEnabled = false;
}
onRender(_, srcTexture: Texture2D, dst: RenderTarget): void {

View File

@@ -1,9 +0,0 @@
{
"intro": { "title": "着色器简介" },
"class": { "title": "Shader 对象" },
"builtins": { "title": "内置着色器" },
"custom": { "title": "自定义着色器" },
"assets": { "title": "Shader 资产" },
"shaderLab": { "title": "ShaderLab" },
"shaderAPI": { "title": "Shader API【实验】" }
}

View File

@@ -1,25 +0,0 @@
---
title: Shader 资产
---
Shader 资产是 Galacean 编辑器项目中定义 Shader 对象的资产,目前包含两种:
- Shader 主文件
以 `.gs` 为后缀名,是 ShaderLab 编译的入口文件。
- Shader Chunk
以 `.glsl` 为后缀名,是可以复用的 ShaderLab 代码片段,通过 `#include` 宏引入。
<Callout type="warning">
`EditorProperties` 和 `EditorMacros` 只能声明在 Shader 主文件内,不能通过 `#include` 宏引入。
</Callout>
## Shader 资产创建
<Image src="https://mdn.alipayobjects.com/huamei_rmtxpm/afts/img/A*namMTLNnCPYAAAAAAAAAAAAADv-7AQ/original" />
编辑器中可以提供了3个 Shader 资产文件模板: `Unlit Shader`, `PBR Shader` 和 `Shader Chunk`。和脚本组件类似,选中 Shader 资产可以在 Inspector 界面预览 Shader 代码,双击或者在代码编辑页面选中可以实时编辑 Shader 代码。
前往 [Shader API 教程](/docs/graphics/shader/shaderAPI/) 了解如何基于模板拓展 Shader。

View File

@@ -1,25 +0,0 @@
---
title: 介绍
---
目前 Galacean 引擎内置了许多常用的 Shader诸如
| 类型 | 描述 |
| :-- | :-- |
| [Unlit ](/docs/graphics/shader/builtins/unlit) | Unlit Shader 适用于烘焙好的模型渲染,她只需要设置一张基本纹理或者颜色,即可展现离线渲染得到的高质量渲染结果,但是缺点是无法实时展现光影交互,因为 Unlit 由纹理决定渲染,不受任何光照影响,可参考 [烘焙教程](/docs/art/bake-blender) 和 [导出 Unlit 教程](/docs/graphics/shader/builtins/unlit) |
| [Blinn Phong ](/docs/graphics/shader/builtins/blinnPhong) | Blinn Phong Shader 适用于那些对真实感没有那么高要求的场景,虽然没有遵循物理,但是其高效的渲染算法和基本齐全的光学部分,可以适用很多的场景。 |
| [PBR ](/docs/graphics/shader/builtins/pbr) | PBR Shader 适合需要真实感渲染的应用场景,因为 PBR 是基于物理的渲染,遵循能量守恒,开发者通过调整金属度、粗糙度、灯光等参数,能够保证渲染效果都是物理正确的。 |
可以在编辑器中直接调试内置着色器的对应属性观察实时渲染效果变化。
<Image src='https://gw.alipayobjects.com/zos/OasisHub/94cf8176-569d-4605-bd73-967b03316c3d/image-20240206173751409.png' />
> 与之对应的,也可以通过设置 PBRMaterial , BlinnPhongMaterial 与 UnlitMaterial 材质的 API 达到相同效果。
| 参数 | 应用 |
| :-- | :-- |
| [isTransparent](/apis/core/#BaseMaterial-isTransparent) | 是否透明。可以设置材质是否透明。如果设置为透明,可以通过 [BlendMode](/apis/core/#BaseMaterial-blendMode) 来设置颜色混合模式。 |
| [alphaCutoff](/apis/core/#BaseMaterial-alphaCutoff) | 透明度裁剪值。可以设置裁剪值,在着色器中,透明度小于此数值的片元将会被裁减,参考 [案例](/embed/blend-mode) |
| [renderFace](/apis/core/#BaseMaterial-renderFace) | 渲染面。可以决定渲染正面、背面、双面。 |
| [blendMode](/apis/core/#BaseMaterial-blendMode) | 颜色混合模式。当设置材质为透明后,可以设置此枚举来决定颜色混合模式,参考 [案例](/embed/blend-mode) |
| [tilingOffset](/apis/core/#BlinnPhongMaterial-tilingOffset) | 纹理坐标的缩放与偏移。是一个 Vector4 数据,分别控制纹理坐标在 uv 方向上的缩放和偏移,参考 [案例](/embed/tiling-offset) |

View File

@@ -1,54 +0,0 @@
---
title: Shader
---
在[着色器简介](/docs/graphics/shader/intro/)我们了解了着色器的基本概念Galacean 引擎基于着色器程序,将其他渲染相关的信息进行了统一封装,形成了 Shader 对象。Shader 对象和 [材质](/docs/graphics/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](/apis/galacean/#Camera-resetReplacementShader),指定渲染管线的`replacementTag`,实现对设置指定 `Tag` 的 `SubShader` 替换的目的。
Tags 可以通过 [SubShader.setTag](/apis/galacean/#SubShader-setTag) 和 [ShaderPass.setTag](/apis/galacean/#ShaderPass-setTag)进行指定ShaderLab 指定 Tag 方式详见[文档](/docs/graphics/shader/shaderLab/syntax/subShader/#tags)
- Passes
一个 SubShader 包含至少一个 ShaderPass 对象。
- RenderStates
SubShader 下所有 ShaderPass 共享的 [RenderState 渲染状态](/docs/graphics/material/composition/#渲染状态)
## ShaderPass
ShaderPass 封装了具体的着色器程序,以及执行最终渲染时的[渲染状态](/docs/graphics/material/composition/#渲染状态)。
<Callout type="info">
同一 SubShader 下的 ShaderPass 按照数组顺序依次渲染,渲染效果逐步叠加,形成 Shader 在当前帧的最终渲染结果。
</Callout>

View File

@@ -1,25 +0,0 @@
<Image src="https://gw.alipayobjects.com/zos/OasisHub/a3f74864-241e-4cd8-9ad4-733c2a0b2cc2/image-20240206153815596.png" />
## 着色器简介
着色器(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[帧图像]
```
<figcaption style={{"text-align":"center", color: "#889096","font-size":"12px"}}>简化的渲染管线</figcaption>
本章节我们将介绍如下内容:
|小节|内容|
|:--:|:--:|
|[Shader对象](/docs/graphics/shader/class/)|引擎中Shader对象的概括和基本用法|
|[内置着色器](/docs/graphics/shader/builtins/intro/)|引擎内置的常用着色器|
|[Shader资产](/docs/graphics/shader/assets/)|在编辑器中如何创建、修改Shader资产|
|[ShaderLab](/docs/graphics/shader/shaderLab/intro/)|一种更为便捷的创建Shader的方式|

View File

@@ -1,6 +0,0 @@
{
"intro": "介绍",
"create": "创建",
"syntax": "语法标准",
"usage": "使用"
}

View File

@@ -1,35 +0,0 @@
---
title: 创建
---
## 在编辑器中创建
编辑器中可以添加 3 种 ShaderLab 模板: `Unlit`、`PBR`、和 着色器片段
<Image
src="https://mdn.alipayobjects.com/huamei_rmtxpm/afts/img/A*namMTLNnCPYAAAAAAAAAAAAADv-7AQ/original"
style={{ width: "50%" }}
/>
其中 **`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);
```

View File

@@ -1,38 +0,0 @@
---
title: ShaderLab 语法标准
---
## 在编辑器中编辑着色器
双击我们在上一步创建的着色器资产即可跳转到代码编辑页
> 未来版本会推出 Galacean VSCode 插件,该插件会为`ShaderLab`提供语法检测和自动补全功能以及代码同步功能,敬请期待
<Image
src="https://mdn.alipayobjects.com/huamei_aftkdx/afts/img/A*c4yyRboqBSwAAAAAAAAAAAAADteEAQ/fmt.webp"
style={{ zoom: "50%" }}
/>
## 语法标准
`ShaderLab` 语法骨架如下:
```glsl
Shader "ShaderName" {
...
Editor {
...
}
...
SubShader "SubShaderName" {
...
Pass "PassName" {
...
}
...
}
...
}
```
主要包含 [Shader](/docs/graphics/shader/shaderLab/syntax/shader/)[SubShader](/docs/graphics/shader/shaderLab/syntax/subShader/) 和 [ShaderPass](/docs/graphics/shader/shaderLab/syntax/pass/) 模块。

View File

@@ -1,36 +0,0 @@
---
title: SubShader
---
```glsl
SubShader "SubShaderName" {
...
// 全局变量区:变量声明,结构体声明,渲染状态声明
...
Tags {ReplaceTag = "opaque"}
UsePass "ShaderName/SubShaderName/PassName"
Pass "PassName" {
...
}
}
```
## Tags
在 [Shader 对象](/docs/graphics/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 |