From f001ed6f67dd709d0a6cdee659f3c2e24f188ddc Mon Sep 17 00:00:00 2001 From: zhuxudong Date: Wed, 15 Jan 2025 18:14:24 +0800 Subject: [PATCH] docs: add post-processing related --- docs/en/core/scene.md | 48 +++--- docs/en/graphics/camera/component.md | 1 + .../postProcess/customPostProcess.mdx | 149 ++++++++++++++++++ docs/en/graphics/postProcess/postProcess.mdx | 118 ++++++-------- docs/zh/core/scene.md | 35 ++-- docs/zh/graphics/camera/component.md | 1 + .../postProcess/customPostProcess.mdx | 149 ++++++++++++++++++ docs/zh/graphics/postProcess/postProcess.mdx | 90 +++++------ 8 files changed, 424 insertions(+), 167 deletions(-) create mode 100644 docs/en/graphics/postProcess/customPostProcess.mdx create mode 100644 docs/zh/graphics/postProcess/customPostProcess.mdx diff --git a/docs/en/core/scene.md b/docs/en/core/scene.md index f455c2454..d5bc65e64 100644 --- a/docs/en/core/scene.md +++ b/docs/en/core/scene.md @@ -19,7 +19,7 @@ Right-click in the **[Assets Panel](/en/docs/assets/interface)** (or the + sign ### Properties Panel -image-20240718190944508 +image-20240718190944508 ### Ambient Light @@ -33,29 +33,24 @@ For details, please refer to the [Background Tutorial](/en/docs/graphics/backgro For details, please refer to the [Shadow Tutorial](/en/docs/graphics/light/shadow/). -### Post-Processing - -For details, please refer to the [Post-Processing Tutorial](/en/docs/graphics/postProcess/postProcess/). - ### Fog You can add **linear, exponential, exponential squared** 3 types of fog to the entire scene: ![Fog](https://gw.alipayobjects.com/zos/OasisHub/224fbc16-e60c-47ca-845b-5f7c09563c83/2024-03-19%25252018.08.23.gif) - ## Script Usage -| Property Name | Description | -| :-------------------------------------------- | :---------- | -| [scenes](/apis/core/#SceneManager-scenes) | Scene list | +| Property Name | Description | +| :---------------------------------------- | :---------- | +| [scenes](/apis/core/#SceneManager-scenes) | Scene list | -| Method Name | Description | -| :--------------------------------------------------- | :---------- | -| [addScene](/apis/core/#SceneManager-addScene) | Add scene | -| [removeScene](/apis/core/#SceneManager-removeScene) | Remove scene| -| [mergeScenes](/apis/core/#SceneManager-mergeScenes) | Merge scenes| -| [loadScene](/apis/core/#SceneManager-loadScene) | Load scene | +| Method Name | Description | +| :-------------------------------------------------- | :----------- | +| [addScene](/apis/core/#SceneManager-addScene) | Add scene | +| [removeScene](/apis/core/#SceneManager-removeScene) | Remove scene | +| [mergeScenes](/apis/core/#SceneManager-mergeScenes) | Merge scenes | +| [loadScene](/apis/core/#SceneManager-loadScene) | Load scene | ### Loading a Scene @@ -64,11 +59,9 @@ If you want to load a **Scene** asset as a scene in the application, you can use ```typescript const sceneUrl = "..."; -engine.resourceManager - .load({ type: AssetType.Scene, url: "..." }) - .then((scene) => { - engine.sceneManager.addScene(scene); - }); +engine.resourceManager.load({ type: AssetType.Scene, url: "..." }).then((scene) => { + engine.sceneManager.addScene(scene); +}); ``` ### Getting Scene Objects @@ -126,12 +119,12 @@ Call `scene.destroy()` to destroy a scene. The destroyed scene will also be auto ### Entity Tree Management -| Method Name | Description | -| :------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------- | -| [createRootEntity](/apis/core/#Scene-createRootEntity) | The newly created _scene_ does not have a root entity by default and needs to be created manually | -| [addRootEntity](/apis/core/#Scene-addRootEntity) | You can directly create a new entity or add an existing entity | -| [removeRootEntity](/apis/core/#Scene-removeRootEntity) | Remove the root entity | -| [getRootEntity](/apis/core/#Scene-getRootEntity) | Find the root entity, you can get all root entities or a single entity object. Note that all entities are read-only arrays and cannot change length or order | +| Method Name | Description | +| :-- | :-- | +| [createRootEntity](/apis/core/#Scene-createRootEntity) | The newly created _scene_ does not have a root entity by default and needs to be created manually | +| [addRootEntity](/apis/core/#Scene-addRootEntity) | You can directly create a new entity or add an existing entity | +| [removeRootEntity](/apis/core/#Scene-removeRootEntity) | Remove the root entity | +| [getRootEntity](/apis/core/#Scene-getRootEntity) | Find the root entity, you can get all root entities or a single entity object. Note that all entities are read-only arrays and cannot change length or order | ```typescript const engine = await WebGLEngine.create({ canvas: "demo" }); @@ -161,4 +154,7 @@ const cameraEntity = rootEntity.createChild("camera"); cameraEntity.addComponent(Camera); ``` + +``` + ``` diff --git a/docs/en/graphics/camera/component.md b/docs/en/graphics/camera/component.md index 547bae9bf..53dd5ad0b 100644 --- a/docs/en/graphics/camera/component.md +++ b/docs/en/graphics/camera/component.md @@ -81,6 +81,7 @@ The functionality corresponding to each property is as follows: | | [msaaSamples](/apis/core/#Camera-msaaSamples) | Number of samples for multi-sample anti-aliasing, effective only when the standalone canvas is enabled, such as `enableHDR`, `enablePostProcess`, `opaqueTextureEnabled`. | | | [enableHDR](/apis/core/#Camera-enableHDR) | Whether to enable HDR rendering, allowing the shader's output color to be stored using floating-point numbers, providing a wider range of values for post-processing and other scenarios. | | | [enablePostProcess](/apis/core/#Camera-enablePostProcess) | Whether to enable post-processing. For post-processing configuration, see [Post-Processing Tutorial](/en/docs/graphics/postProcess/postProcess). | +| | [postProcessMask](/apis/core/#Camera-postProcessMask) | Post-processing mask, which determines the effective post-processing components. For post-processing configuration, [Post-Processing Tutorial](/en/docs/graphics/postProcess/postProcess). | ### Culling Mask diff --git a/docs/en/graphics/postProcess/customPostProcess.mdx b/docs/en/graphics/postProcess/customPostProcess.mdx new file mode 100644 index 000000000..548bb9639 --- /dev/null +++ b/docs/en/graphics/postProcess/customPostProcess.mdx @@ -0,0 +1,149 @@ +--- +order: 2 +title: Custom Post-Processing +--- + +In the post-processing system, the effect ([Effect](/apis/core/#PostProcessEffect)) is responsible for maintaining the data layer, and the pipeline ([Pass](/apis/core/#PostProcessPass)) is responsible for writing the rendering logic. In the pipeline, calling the [getBlendEffect](/apis/core/#PostProcessManager-getBlendEffect) method can get the final post-processing data after **global/local** mixing. + + + +The engine has built-in [PostProcessUberPass](/apis/core/#PostProcessUberPass), which is used with [BloomEffect](/apis/core/#BloomEffect) and [TonemappingEffect](/apis/core/#TonemappingEffect) data. If you want to customize post-processing effects, we need to create a new Pass and then create an Effect based on whether the data needs to be fused. + +## A Demo + +Here we will simply implement a grayscale image post-processing effect~ + + + +### 1. Shader Writing + +The algorithm is not special, but you need to pay attention to `renderer_BlitTexture` This built-in variable is the post-processing rendering result of the previous Pass. Here it is the result after Bloom and Tonemapping. We display this result in grayscale. + +```ts showLineNumbers {14} +const customShader = Shader.create( + "Gray Scale Shader", + ` + attribute vec4 POSITION_UV; + varying vec2 v_uv; + + void main() { + gl_Position = vec4(POSITION_UV.xy, 0.0, 1.0); + v_uv = POSITION_UV.zw; + } + `, + ` + varying vec2 v_uv; + uniform sampler2D renderer_BlitTexture; + + void main(){ + vec4 color = texture2D(renderer_BlitTexture, v_uv); + float grayScale = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b; + gl_FragColor = vec4(vec3(grayScale), 1.0); + } + ` +); +``` + +### 2. Create a new Pass + +We create a new Pass, directly [Blitter](/apis/core/#Blitter) to the screen in the [onRender hook](/apis/core/#PostProcessUberPass-onRender), and then add this Pass to the engine. + +```ts showLineNumbers {10,15} +class CustomPass extends PostProcessPass { + private _blitMaterial: Material; + + constructor(engine: Engine) { + super(engine); + this._blitMaterial = new Material(this.engine, customShader); + } + + onRender(_, srcTexture: Texture2D, dst: RenderTarget): void { + Blitter.blitTexture(this.engine, srcTexture, dst, undefined, undefined, this._blitMaterial, 0); + } +} + +const customPass = new CustomPass(engine); +engine.addPostProcessPass(customPass); +``` + +The execution order of Pass is executed after Uber Pass by default, that is [`PostProcessPassEvent.AfterUber`](/apis/core/#PostProcessPassEvent-AfterUber), we can also manually modify the execution order of the pipeline: + +```ts +customPass.event = PostProcessPassEvent.BeforeUber; +``` + +Whether the Pass is effective is determined by the Pass's [isActive](/apis/core/#PostProcessUberPass-isActive) by default. We can also modify the effectiveness logic, such as whether the intensity is greater than 0: + +```ts showLineNumbers {2-9} +class CustomPass extends PostProcessPass { + override isValid(postProcessManager: PostProcessManager): boolean { + if (!this.isActive) { + return false; + } + + const customEffectBlend = postProcessManager.getBlendEffect(CustomEffect); + return customEffectBlend?.intensity > 0; + } +} +``` + +### 3. Blend data + +The above steps 1 and 2 can already customize the post-processing effect. Here is an advanced version of Blend data. + +Take `intensity` as an example. We define a `CustomEffect`, which is specifically used to fuse intensity. The data to be fused is also very simple. The engine has encapsulated a series of post-processing parameters, such as [floating point type parameters](/apis/core/#PostProcessEffectFloatParameter). + +```ts showLineNumbers {2,7} +class CustomEffect extends PostProcessEffect { + intensity = new PostProcessEffectFloatParameter(0.8); +} + +// Add this effect to the post-processing component. postProcess can be created separately, +// or it can be the same as Bloom and other effects. It depends on the Blend requirements~ +postProcess.addEffect(CustomEffect); +``` + +After defining the data, you need to change the `onRender` hook of the custom Pass to get the Blend data: + +```ts showLineNumbers {3-6} +class CustomPass extends PostProcessPass { + onRender(camera: Camera, srcTexture: Texture2D, dst: RenderTarget): void { + const postProcessManager = camera.scene.postProcessManager; + const customEffectBlend = postProcessManager.getBlendEffect(CustomEffect); + if (customEffectBlend) { + this._blitMaterial.shaderData.setFloat("u_intensity", customEffectBlend.intensity.value); + } + + Blitter.blitTexture(this.engine, srcTexture, dst, undefined, undefined, this._blitMaterial, 0); + } +} +``` + +As you can see, we continuously set the fused intensity in the `onRender` hook of the custom pipeline, and then consume this data in the shader: + +```ts showLineNumbers {8,12} +const customShader = Shader.create( + "Gray Scale Shader", + ` + ...... + `, + ` + ...... + uniform float u_intensity; + + void main(){ + ...... + gl_FragColor = vec4(mix(color.rgb, vec3(grayScale), u_intensity), 1.0); + } + ` +); +``` + +If your post-processing component is in local mode, we can also use [Blend Distance](/apis/core/#PostProcess-blendDistance) to set the distance at which the camera is close to the collision body to start blending: + + diff --git a/docs/en/graphics/postProcess/postProcess.mdx b/docs/en/graphics/postProcess/postProcess.mdx index ba040c1a1..ea59b7af4 100644 --- a/docs/en/graphics/postProcess/postProcess.mdx +++ b/docs/en/graphics/postProcess/postProcess.mdx @@ -3,95 +3,77 @@ order: 0 title: Post Process Overview --- -The post-processing system can "process" the results of scene rendering. +The post-processing system can "process" the results rendered by the camera. - - +## Post-Processing Configuration -## Use post-processing +There are two modes for post-processing: -### 1. Post-processing configuration +- Global Mode: Affects all cameras in the current scene. +- Local Mode: Only effective when the camera is within the collision range of the post-processing entity. -Post-processing configuration is uniformly placed in [scene](/en/docs/core/scene) panel, in order to prevent performance waste, the default **turn off**, users only need to turn on the main switch to activate all post-processing effects: +The post-processing component has the following properties to control effects, modes, blending distances, etc.: - +| Property | Description | +| :-- | :-- | +| [isGlobal](/apis/core/#PostProcess-isGlobal) | Controls whether this post-processing component is in global or local mode. | +| [Blend Distance](/apis/core/#PostProcess-blendDistance) | In local mode, controls how close the camera must be to the collider before blending effects begins. | +| [Priority](/apis/core/#PostProcess-priority) | When there are multiple post-processing components in the scene, a higher priority means blending/overriding starts later. | +| [Layer](/apis/core/#PostProcess-layer) | Used with the camera's [post-processing mask](/apis/core/#Camera-postProcessMask) to determine which post-processing components are effective. | +| [Add Effect](/apis/core/#PostProcess-addEffect) | Adds post-processing effects. | + +## Using Post-Processing + +### 1. Adding a Post-Processing Component + +In the hierarchy panel, several modes for global and local post-processing are preset; simply select and add to use. + + + +Of course, you can also manually add post-processing components. Local mode needs to be used with colliders: + + - For specific post-processing effect configuration, please refer to [Post-processing Effect + For specific post-processing effects configuration, please refer to the [Post-Processing Effects List](/en/docs/graphics/postProcess/effects) - - As of version 1.3, the engine does not expose public APIs (because after supporting post-processing extensions, the - APIs may change). We recommend that users perform post-processing operations in the editor. If you want to use the - internal experimental interface, you can call the following code: - +### 2. Camera Switch -```typescript -// Get the post-processing manager -// @ts-ignore -const postProcessManager = scene._postProcessManager; -// Get BloomEffect -const bloomEffect = postProcessManager._bloomEffect as BloomEffect; -// Get TonemappingEffect -const tonemappingEffect = postProcessManager._tonemappingEffect as TonemappingEffect; +The camera preview area is controlled by the **Camera Component**. In the camera component, the following properties will also affect the post-processing effects: -// Activate the main switch -postProcessManager.isActive = true; - -// Adjust BloomEffect properties -bloomEffect.enabled = true; -bloomEffect.downScale = BloomDownScaleMode.Half; -bloomEffect.threshold = 0.9; -bloomEffect.scatter = 0.7; -bloomEffect.intensity = 1; -bloomEffect.tint.set(1, 1, 1, 1); - -// Adjust TonemappingEffect properties -tonemappingEffect.enabled = true; -tonemappingEffect.mode = TonemappingMode.ACES; -``` - -### 2. Camera switch - -The camera preview area is controlled by the **camera component**. In the camera component, the following properties will affect the post-processing effect: - -- **Post-processing switch**: You can turn on or off the camera's post-processing effect. The overall switch and specific configuration of post-processing are in the [scene](/en/docs/core/scene) panel. - -- **HDR switch**: In HDR mode, the output color is allowed to be stored using floating point numbers, which can obtain a wider range of values ​​for scenes such as [bloom effects](/en/docs/graphics/postProcess/effects). - -- **MSAA configuration**: You can adjust the settings of multi-sampling anti-aliasing to improve the quality of the picture such as aliasing. - - +| Property | Description | +| :-- | :-- | +| [Post-Processing Switch](/apis/core/#Camera-enablePostProcess) | Enables or disables the post-processing effects of the camera. | +| [HDR Switch](/apis/core/#Camera-enableHDR) | In HDR mode, allows output colors to be stored using floating-point numbers, providing a broader range of values for [bloom effects](/en/docs/graphics/postProcess/effects) and other scenarios. | +| [MSAA Configuration](/apis/core/#Camera-msaaSamples) | Adjusts the multi-sampling anti-aliasing settings to improve image quality, such as reducing jagged edges. | +| [Post-Processing Mask](/apis/core/#Camera-postProcessMask) | Works with the post-processing component's [layer](/apis/core/#PostProcess-layer) to determine which post-processing components are effective. | - For more camera configurations, refer to [Camera Component](/en/docs/graphics/camera/component) + For more camera configurations, refer to the [Camera Component](/en/docs/graphics/camera/component) ### 3. Viewport Switch -In addition to the camera preview area, the viewport can also see the post-processing effect. The camera in the viewport is independent, but it also has post-processing switches like the camera component (same as above, also pay attention to the switches in the post-processing configuration); the switches in the viewport only affect the view window and do not affect the actual effect of the project export: +In addition to the camera preview area, the viewport can also display post-processing effects. The camera in the viewport is independent but has post-processing configurations similar to the camera component. - + + The switch in the viewport only affects the view window and does not impact the actual effect exported in the project. + -## Recommended configuration for mobile + -Generally speaking, some post-processing configurations in the red box in the figure below will affect performance: +## Best Practices - - -And some camera configurations: - - - -- Regarding the `HDR` switch in the camera, if most of the pixel calculations in the scene do not exceed 1 (for example, HDR maps are not used), try not to turn on HDR. After turning it on, the engine will first render to `R11G11B10_UFloat` format In RenderTarget, rendering to the screen again has performance overhead. -- Regarding the `MSAA` option in the camera, it is recommended to adjust this value only when post-processing is turned on and the anti-aliasing performance is strictly required. The larger the value, the greater the performance overhead. -- In the bloom effect, `Down Scale` defaults to `Half`, that is, the initial downsampling resolution is half of the canvas. If the accuracy requirement is not so high, you can switch to `Quarter` and save 1/4 of the canvas. -- In the tone mapping effect, although `ACES` has better color contrast and saturation, the calculation is more complicated, which may cause serious frame drops on low-end models. You can try to use `Neutral` as an alternative. +- Regarding the `HDR` switch in the camera, if the majority of pixels in the scene do not exceed 1 (e.g., no HDR textures used), avoid enabling HDR. When enabled, the engine first renders to a `R11G11B10_UFloat` format RenderTarget before rendering to the screen, incurring performance overhead. +- Regarding the `MSAA` option in the camera, only adjust this value when post-processing is enabled and strict on anti-aliasing performance. The higher the value, the greater the performance overhead. +- In bloom effects, `Down Scale` defaults to `Half`, meaning the initial downsampled resolution is half that of the canvas. If high precision is not required, switch to `Quarter`, saving to a quarter of the canvas. +- In tone mapping effects, while `ACES` offers better color contrast and saturation, it is computationally complex and may cause significant frame drops on low-end devices. Consider using `Neutral` as an alternative. diff --git a/docs/zh/core/scene.md b/docs/zh/core/scene.md index a71db8f3b..583218f17 100644 --- a/docs/zh/core/scene.md +++ b/docs/zh/core/scene.md @@ -19,7 +19,7 @@ Scene 作为场景单元,可以方便的进行实体树管理,尤其是大 ### 属性面板 -image-20240718190944508 +image-20240718190944508 ### 环境光 @@ -33,25 +33,20 @@ Scene 作为场景单元,可以方便的进行实体树管理,尤其是大 详情请参照[阴影教程](/docs/graphics/light/shadow/)。 -### 后处理 - -详情请参照[后处理教程](/docs/graphics/postProcess/postProcess/)。 - ### 雾化 可以给整个场景增加 **线性、指数、指数平方** 3 种雾化: ![Fog](https://gw.alipayobjects.com/zos/OasisHub/224fbc16-e60c-47ca-845b-5f7c09563c83/2024-03-19%25252018.08.23.gif) - ## 脚本使用 -| 属性名称 | 解释 | -| :--------------------------------------- | :------- | +| 属性名称 | 解释 | +| :---------------------------------------- | :------- | | [scenes](/apis/core/#SceneManager-scenes) | 场景列表 | -| 方法名称 | 解释 | -| :------------------------------------------------- | :------- | +| 方法名称 | 解释 | +| :-------------------------------------------------- | :------- | | [addScene](/apis/core/#SceneManager-addScene) | 添加场景 | | [removeScene](/apis/core/#SceneManager-removeScene) | 移除场景 | | [mergeScenes](/apis/core/#SceneManager-mergeScenes) | 合并场景 | @@ -64,11 +59,9 @@ Scene 作为场景单元,可以方便的进行实体树管理,尤其是大 ```typescript const sceneUrl = "..."; -engine.resourceManager - .load({ type: AssetType.Scene, url: "..." }) - .then((scene) => { - engine.sceneManager.addScene(scene); - }); +engine.resourceManager.load({ type: AssetType.Scene, url: "..." }).then((scene) => { + engine.sceneManager.addScene(scene); +}); ``` ### 获取场景对象 @@ -126,12 +119,12 @@ engine.sceneManager.addScene(destScene); ### 实体树管理 -| 方法名称 | 解释 | -| :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | -| [createRootEntity](/apis/core/#Scene-createRootEntity) | 新创建的 _scene_ 默认没有根实体,需要手动创建 | -| [addRootEntity](/apis/core/#Scene-addRootEntity) | 可以直接新建实体,或者添加已经存在的实体 | -| [removeRootEntity](/apis/core/#Scene-removeRootEntity) | 删除根实体 | -| [getRootEntity](/apis/core/#Scene-getRootEntity) | 查找根实体,可以拿到全部根实体,或者单独的某个实体对象。注意,全部实体是只读数组,不能改变长度和顺序 | +| 方法名称 | 解释 | +| :-- | :-- | +| [createRootEntity](/apis/core/#Scene-createRootEntity) | 新创建的 _scene_ 默认没有根实体,需要手动创建 | +| [addRootEntity](/apis/core/#Scene-addRootEntity) | 可以直接新建实体,或者添加已经存在的实体 | +| [removeRootEntity](/apis/core/#Scene-removeRootEntity) | 删除根实体 | +| [getRootEntity](/apis/core/#Scene-getRootEntity) | 查找根实体,可以拿到全部根实体,或者单独的某个实体对象。注意,全部实体是只读数组,不能改变长度和顺序 | ```typescript const engine = await WebGLEngine.create({ canvas: "demo" }); diff --git a/docs/zh/graphics/camera/component.md b/docs/zh/graphics/camera/component.md index 790e75bcf..43cb56cc2 100644 --- a/docs/zh/graphics/camera/component.md +++ b/docs/zh/graphics/camera/component.md @@ -81,6 +81,7 @@ camera.enableHDR = true; | | [msaaSamples](/apis/core/#Camera-msaaSamples) | 多样本抗锯齿采样样本数量,仅当独立画布开启时才能生效,如 `enableHDR`、`enablePostProcess`、`opaqueTextureEnabled`。 | | | [enableHDR](/apis/core/#Camera-enableHDR) | 是否启用 HDR 渲染,允许 shader 输出的颜色使用浮点数进行存储,可以得到更大范围的值,用于后处理等场景。 | | | [enablePostProcess](/apis/core/#Camera-enablePostProcess) | 是否启用后处理,后处理配置详见[后处理教程](/docs/graphics/postProcess/postProcess)。 | +| | [postProcessMask](/apis/core/#Camera-postProcessMask) | 后处理遮罩,决定生效的后处理组件,后处理配置详见[后处理教程](/docs/graphics/postProcess/postProcess)。 | ### 裁剪遮罩 diff --git a/docs/zh/graphics/postProcess/customPostProcess.mdx b/docs/zh/graphics/postProcess/customPostProcess.mdx new file mode 100644 index 000000000..2c5d55734 --- /dev/null +++ b/docs/zh/graphics/postProcess/customPostProcess.mdx @@ -0,0 +1,149 @@ +--- +order: 2 +title: 自定义后处理 +--- + +在后处理系统中,特效([Effect](/apis/core/#PostProcessEffect)) 负责数据层的维护,管线([Pass](/apis/core/#PostProcessPass))负责渲染逻辑的编写,在管线中调用 [getBlendEffect](/apis/core/#PostProcessManager-getBlendEffect) 方法可以拿到经过 **全局/局部** 混合后的最终后处理数据。 + + + +引擎内置了 [PostProcessUberPass](/apis/core/#PostProcessUberPass),搭配 [BloomEffect](/apis/core/#BloomEffect) 和 [TonemappingEffect](/apis/core/#TonemappingEffect) 的数据使用,如果想要自定义后处理特效,我们需要新建一个 Pass,然后根据是否需要融合数据来创建 Effect。 + +## 一个 Demo + +这里就简单地实现一个灰度图的后处理效果吧~ + + + +### 1. Shader 编写 + +算法没有特殊的, 需要注意 `renderer_BlitTexture` 这个内置变量就是上一个 Pass 的后处理渲染结果,在此处就是 Bloom 和 Tonemapping 后的结果,我们针对这个结果进行了灰度显示。 + +```ts showLineNumbers {14} +const customShader = Shader.create( + "Gray Scale Shader", + ` + attribute vec4 POSITION_UV; + varying vec2 v_uv; + + void main() { + gl_Position = vec4(POSITION_UV.xy, 0.0, 1.0); + v_uv = POSITION_UV.zw; + } + `, + ` + varying vec2 v_uv; + uniform sampler2D renderer_BlitTexture; + + void main(){ + vec4 color = texture2D(renderer_BlitTexture, v_uv); + float grayScale = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b; + gl_FragColor = vec4(vec3(grayScale), 1.0); + } + ` +); +``` + +### 2. 新建 Pass + +我们新建一个 Pass,在 [onRender 钩子](/apis/core/#PostProcessUberPass-onRender) 里面直接 [Blitter](/apis/core/#Blitter) 到屏幕,然后将这个 Pass 添加到引擎中。 + +```ts showLineNumbers {10,15} +class CustomPass extends PostProcessPass { + private _blitMaterial: Material; + + constructor(engine: Engine) { + super(engine); + this._blitMaterial = new Material(this.engine, customShader); + } + + onRender(_, srcTexture: Texture2D, dst: RenderTarget): void { + Blitter.blitTexture(this.engine, srcTexture, dst, undefined, undefined, this._blitMaterial, 0); + } +} + +const customPass = new CustomPass(engine); +engine.addPostProcessPass(customPass); +``` + +Pass 的执行顺序默认在 Uber Pass 的后面执行,即 [`PostProcessPassEvent.AfterUber`](/apis/core/#PostProcessPassEvent-AfterUber),我们也可以手动修改管线的执行顺序: + +```ts +customPass.event = PostProcessPassEvent.BeforeUber; +``` + +Pass 是否生效默认是根据 Pass 的 [isActive](/apis/core/#PostProcessUberPass-isActive) 来决定的,我们也可以修改生效逻辑,比如强度是否大于 0 : + +```ts showLineNumbers {2-9} +class CustomPass extends PostProcessPass { + override isValid(postProcessManager: PostProcessManager): boolean { + if (!this.isActive) { + return false; + } + + const customEffectBlend = postProcessManager.getBlendEffect(CustomEffect); + return customEffectBlend?.intensity > 0; + } +} +``` + +### 3. 融合数据 + +上述 1、2 步骤已经能够自定义后处理效果,这里再来一个进阶版的融合数据。 + +拿 `intensity` 举例,我们定义一个 `CustomEffect`,专门用来融合强度,需要融合的数据也很简单,引擎已经封装了一系列后处理参数,如[浮点类型参数](/apis/core/#PostProcessEffectFloatParameter)。 + +```ts showLineNumbers {2,7} +class CustomEffect extends PostProcessEffect { + intensity = new PostProcessEffectFloatParameter(0.8); +} + +// 将这个 effect 添加到后处理组件中,postProcess 可以是单独新建的, +// 也可以是跟 Bloom 等 effect 同一个,具体看融合的需求~ +postProcess.addEffect(CustomEffect); +``` + +定义好数据后,需要在自定义 Pass 的 `onRender` 钩子中,改成获取融合数据: + +```ts showLineNumbers {3-6} +class CustomPass extends PostProcessPass { + onRender(camera: Camera, srcTexture: Texture2D, dst: RenderTarget): void { + const postProcessManager = camera.scene.postProcessManager; + const customEffectBlend = postProcessManager.getBlendEffect(CustomEffect); + if (customEffectBlend) { + this._blitMaterial.shaderData.setFloat("u_intensity", customEffectBlend.intensity.value); + } + + Blitter.blitTexture(this.engine, srcTexture, dst, undefined, undefined, this._blitMaterial, 0); + } +} +``` + +可以看到,我们在自定义管线的 `onRender` 钩子中,不断设置融合后的强度,然后在 shader 中消费这个数据即可: + +```ts showLineNumbers {8,12} +const customShader = Shader.create( + "Gray Scale Shader", + ` + ...... + `, + ` + ...... + uniform float u_intensity; + + void main(){ + ...... + gl_FragColor = vec4(mix(color.rgb, vec3(grayScale), u_intensity), 1.0); + } + ` +); +``` + +如果你的后处理组件是局部模式,我们还可以通过 [Blend Distance](/apis/core/#PostProcess-blendDistance) 来设置相机靠近碰撞体多少距离时开始混合: + + diff --git a/docs/zh/graphics/postProcess/postProcess.mdx b/docs/zh/graphics/postProcess/postProcess.mdx index a3c1d43f7..ffda0d71b 100644 --- a/docs/zh/graphics/postProcess/postProcess.mdx +++ b/docs/zh/graphics/postProcess/postProcess.mdx @@ -3,83 +3,69 @@ order: 0 title: 后处理总览 --- -后处理系统可以对场景渲染的结果进行“加工”。 +后处理系统可以对相机渲染的结果进行“加工”。 +## 后处理配置 + +后处理有两种模式: + +- 全局模式:影响当前场景中的所有相机。 +- 局部模式:只有当相机靠近后处理实体的碰撞体范围时才生效。 + +后处理组件拥有以下属性,可以控制后处理的特效、模式、混合距离等: + +| 属性 | 作用 | +| :-- | :-- | +| [全局模式](/apis/core/#PostProcess-isGlobal) | 控制这个后处理组件是全局还是局部模式。 | +| [混合距离](/apis/core/#PostProcess-blendDistance) | 局部模式时,用来控制相机靠近碰撞体多少距离时,开始混合特效。 | +| [优先级](/apis/core/#PostProcess-priority) | 当场景中有多个后处理组件时,优先级越高,越后面开始覆盖/混合。 | +| [层级](/apis/core/#PostProcess-layer) | 配合相机的[后处理遮罩](/apis/core/#Camera-postProcessMask) 使用,决定生效的后处理组件。 | +| [添加特效](/apis/core/#PostProcess-addEffect) | 添加后处理特效。 | + ## 使用后处理 -### 1.后处理配置 +### 1.添加后处理组件 -后处理配置统一放在 [场景](/docs/core/scene) 面板下,为了防止性能浪费,默认**关闭总开关**,用户只需要打开总开关,就能激活所有后处理效果: +在层级面板,预设了全局、局部后处理的几种模式,选择添加即可直接使用。 - + + +当然,也可以手动添加后处理组件,局部模式需要搭配碰撞体进行使用: + + 具体的后处理效果配置,请参考 [后处理效果列表](/docs/graphics/postProcess/effects) - - 截止 1.3 版本,引擎没有暴露公共 API(因为支持后处理拓展后,API - 可能会产生变动),我们建议用户在编辑器进行后处理操作。如果想使用内部实验接口,可以调用以下代码: - - -```typescript -// 获取后处理管理器 -// @ts-ignore -const postProcessManager = scene._postProcessManager; -// 获取 BloomEffect -const bloomEffect = postProcessManager._bloomEffect as BloomEffect; -// 获取 TonemappingEffect -const tonemappingEffect = postProcessManager._tonemappingEffect as TonemappingEffect; - -// 激活总开关 -postProcessManager.isActive = true; - -// 调整 BloomEffect 属性 -bloomEffect.enabled = true; -bloomEffect.downScale = BloomDownScaleMode.Half; -bloomEffect.threshold = 0.9; -bloomEffect.scatter = 0.7; -bloomEffect.intensity = 1; -bloomEffect.tint.set(1, 1, 1, 1); - -// 调整 TonemappingEffect 属性 -tonemappingEffect.enabled = true; -tonemappingEffect.mode = TonemappingMode.ACES; -``` - ### 2.相机开关 -相机预览区受**相机组件**控制,相机组件中,以下属性会影响后处理效果: +相机预览区受**相机组件**控制,在相机组件中,以下属性也会影响后处理效果: -- **后处理开关**:可以开启或关闭相机的后期处理效果,后处理的总开关和具体配置在 [场景](/docs/core/scene) 面板。 -- **HDR 开关**:HDR 模式下,允许输出颜色使用浮点数进行存储,可以得到更大范围的值,用于[泛光特效](/docs/graphics/postProcess/effects)等场景。 -- **MSAA 配置**:可以调整多重采样抗锯齿的设置,改善锯齿等画面质量。 - - +| 属性 | 作用 | +| :-- | :-- | +| [后处理开关](/apis/core/#Camera-enablePostProcess) | 可以开启或关闭相机的后期处理效果。 | +| [HDR 开关](/apis/core/#Camera-enableHDR) | HDR 模式下,允许输出颜色使用浮点数进行存储,可以得到更大范围的值,用于[泛光特效](/docs/graphics/postProcess/effects)等场景。 | +| [MSAA 配置](/apis/core/#Camera-msaaSamples) | 可以调整多重采样抗锯齿的设置,改善锯齿等画面质量。 | +| [后处理遮罩](/apis/core/#Camera-postProcessMask) | 配合后处理组件的[层级](/apis/core/#PostProcess-layer) 使用,决定生效的后处理组件。 | 相机更多配置参考 [相机组件](/docs/graphics/camera/component) ### 3.视图区开关 -除了相机预览区,视图区也能看到后处理效果。视图区的相机是独立的,但是也和相机组件一样拥有后处理等开关(同上,也要注意后处理配置中的开关);视图区的开关只会影响视图窗口,并不会影响项目导出的真实效果: +除了相机预览区,视图区也能看到后处理效果。视图区的相机是独立的,但是也和相机组件一样拥有后处理等配置。 - +视图区的开关只会影响视图窗口,并不会影响项目导出的真实效果 + + ## 最佳实践 -一般来说,下图红框内的一些后处理配置会影响到性能: - - - -以及相机的部分配置: - - - - 关于相机中 `HDR` 开关,如果场景中绝大部分像素计算没有超过 1(比如没有使用 HDR 贴图), 尽量别开启 HDR,开启后引擎会先渲染到 `R11G11B10_UFloat` 格式的 RenderTarget 中,再渲染到屏幕上,有性能开销。 - 关于相机中的 `MSAA` 选项,仅当开启了后处理,且对锯齿表现要求严格的情况下,才建议调整这个值,值越大,性能开销越大。 - 泛光特效中,`Down Scale` 默认为 `Half`,即初始降采样的分辨率为画布的一半,如果对精度要求没那么高,可以切换为 `Quarter`,节省为画布的 1/4。