-
-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2511 from zhuxudong/document/post-process
[Document] post-processing related
- Loading branch information
Showing
10 changed files
with
553 additions
and
198 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
--- | ||
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. | ||
|
||
```mermaid | ||
graph TD; | ||
subgraph Pass | ||
A1[Custom Pass ...] | ||
A2[Uber Pass] | ||
A3[Custom Pass ...] | ||
end | ||
subgraph Effect | ||
B1[Bloom Effect] | ||
B2[Tonemapping Effect] | ||
B3[Custom Effect] | ||
end | ||
A1 --> A2 --> A3 | ||
B1 --> B2 --> B3 | ||
A1 ---|Blend| B1 | ||
``` | ||
|
||
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~ | ||
|
||
<Comparison | ||
leftSrc="https://gw.alipayobjects.com/zos/OasisHub/f5d3ea3d-47a4-4618-b3d6-0ea46321e786/image-20250115162952605.png" | ||
leftText="Uber Pass" | ||
rightSrc="https://gw.alipayobjects.com/zos/OasisHub/75ccba72-b70b-49f6-812a-e00305e89201/image-20250115163026345.png" | ||
rightText="Uber Pass + Custom Pass" | ||
/> | ||
|
||
### 1. Add script | ||
|
||
Let's create a script first. Next, we will write our custom post-processing Shader and Pass in this script file. | ||
|
||
<Image src="https://gw.alipayobjects.com/zos/OasisHub/6df5fd1c-a24c-4e32-a62e-841b61fe76c7/image-20250124111456360.png" /> | ||
|
||
We refer to [Adding post-processing methods](/en/docs/graphics/postProcess/postProcess/#1-adding-a-post-processing-component) to add global or local post-processing components, and hang the script on this entity: | ||
|
||
<Image src="https://gw.alipayobjects.com/zos/OasisHub/62a36df2-fdc5-4c13-9a32-c41f963d18b5/image-20250124112043221.png" /> | ||
|
||
### 2. 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} filename="CustomPostProcessPass.ts" | ||
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); | ||
} | ||
` | ||
); | ||
``` | ||
|
||
### 3. 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} filename="CustomPostProcessPass.ts" | ||
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 filename="CustomPostProcessPass.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} filename="CustomPostProcessPass.ts" | ||
class CustomPass extends PostProcessPass { | ||
override isValid(postProcessManager: PostProcessManager): boolean { | ||
if (!this.isActive) { | ||
return false; | ||
} | ||
|
||
const customEffectBlend = postProcessManager.getBlendEffect(CustomEffect); | ||
return customEffectBlend?.intensity > 0; | ||
} | ||
} | ||
``` | ||
|
||
### 4. Blend data | ||
|
||
The above steps 2 and 3 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} filename="CustomPostProcessPass.ts" | ||
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} filename="CustomPostProcessPass.ts" | ||
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} filename="CustomPostProcessPass.ts" | ||
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: | ||
|
||
<Image src="https://gw.alipayobjects.com/zos/OasisHub/76b084c1-f517-47d7-8067-7f838db002f8/2025-01-15%25252017.38.30.gif" /> |
Oops, something went wrong.