Skip to content

Commit a69eb60

Browse files
authored
Support post process (galacean#2129)
* feat: support bloom shader * feat: support bloom shader
1 parent a31be29 commit a69eb60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1907
-99
lines changed

e2e/case/.initPostProcessEnv.ts

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
AmbientLight,
3+
AssetType,
4+
BackgroundMode,
5+
Camera,
6+
GLTFResource,
7+
PrimitiveMesh,
8+
SkyBoxMaterial,
9+
Texture2D,
10+
Vector3,
11+
WebGLEngine
12+
} from "@galacean/engine";
13+
import { initScreenshot, updateForE2E } from "./.mockForE2E";
14+
15+
export async function initPostProcessEnv(
16+
callback: (camera: Camera, resArray: [GLTFResource, AmbientLight, Texture2D]) => void
17+
) {
18+
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
19+
engine.canvas.resizeByClientSize();
20+
21+
const scene = engine.sceneManager.activeScene;
22+
const rootEntity = scene.createRootEntity();
23+
24+
//Create camera
25+
const cameraNode = rootEntity.createChild("camera_node");
26+
cameraNode.transform.position.set(4, 0, 6);
27+
cameraNode.transform.lookAt(new Vector3(1, 0, 0));
28+
const camera = cameraNode.addComponent(Camera);
29+
30+
Promise.all([
31+
engine.resourceManager
32+
.load<GLTFResource>("https://gw.alipayobjects.com/os/bmw-prod/a1da72a4-023e-4bb1-9629-0f4b0f6b6fc4.glb")
33+
.then((glTF) => {
34+
const defaultSceneRoot = glTF.instantiateSceneRoot();
35+
rootEntity.addChild(defaultSceneRoot);
36+
return glTF;
37+
}),
38+
engine.resourceManager
39+
.load<AmbientLight>({
40+
type: AssetType.Env,
41+
url: "https://gw.alipayobjects.com/os/bmw-prod/89c54544-1184-45a1-b0f5-c0b17e5c3e68.bin"
42+
})
43+
.then((ambientLight) => {
44+
scene.ambientLight = ambientLight;
45+
const sky = scene.background.sky;
46+
const skyMaterial = new SkyBoxMaterial(engine);
47+
scene.background.mode = BackgroundMode.Sky;
48+
49+
sky.material = skyMaterial;
50+
sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
51+
skyMaterial.texture = ambientLight.specularTexture;
52+
skyMaterial.textureDecodeRGBM = true;
53+
return ambientLight;
54+
}),
55+
engine.resourceManager.load<Texture2D>({
56+
type: AssetType.Texture2D,
57+
url: "https://mdn.alipayobjects.com/huamei_dmxymu/afts/img/A*tMeTQ4Mx60oAAAAAAAAAAAAADuuHAQ/original"
58+
})
59+
]).then((resArray) => {
60+
callback(camera, resArray);
61+
62+
updateForE2E(engine);
63+
64+
initScreenshot(engine, camera);
65+
});
66+
});
67+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @title Bloom + HDR + ACES Tonemapping
3+
* @category PostProcess
4+
*/
5+
import { Camera, TonemappingMode } from "@galacean/engine";
6+
import { initPostProcessEnv } from "./.initPostProcessEnv";
7+
8+
initPostProcessEnv((camera: Camera, resArray) => {
9+
const [_, __, dirtTexture] = resArray;
10+
const scene = camera.scene;
11+
12+
camera.enablePostProcess = true;
13+
camera.enableHDR = true;
14+
// @ts-ignore
15+
const bloomEffect = scene._postProcessManager._bloomEffect;
16+
// @ts-ignore
17+
const tonemappingEffect = scene._postProcessManager._tonemappingEffect;
18+
19+
bloomEffect.enabled = true;
20+
tonemappingEffect.enabled = true;
21+
22+
bloomEffect.threshold = 0.5;
23+
bloomEffect.dirtTexture = dirtTexture;
24+
tonemappingEffect.mode = TonemappingMode.ACES;
25+
});
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @title Bloom + HDR + Neutral Tonemapping
3+
* @category PostProcess
4+
*/
5+
import { Camera, TonemappingMode } from "@galacean/engine";
6+
import { initPostProcessEnv } from "./.initPostProcessEnv";
7+
8+
initPostProcessEnv((camera: Camera, resArray) => {
9+
const [_, __, dirtTexture] = resArray;
10+
const scene = camera.scene;
11+
12+
camera.enablePostProcess = true;
13+
camera.enableHDR = true;
14+
// @ts-ignore
15+
const bloomEffect = scene._postProcessManager._bloomEffect;
16+
// @ts-ignore
17+
const tonemappingEffect = scene._postProcessManager._tonemappingEffect;
18+
19+
bloomEffect.enabled = true;
20+
tonemappingEffect.enabled = true;
21+
22+
bloomEffect.threshold = 0.5;
23+
bloomEffect.dirtTexture = dirtTexture;
24+
tonemappingEffect.mode = TonemappingMode.Neutral;
25+
});
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* @title Bloom + LDR + Neutral Tonemapping
3+
* @category PostProcess
4+
*/
5+
import { Camera, TonemappingMode } from "@galacean/engine";
6+
import { initPostProcessEnv } from "./.initPostProcessEnv";
7+
8+
initPostProcessEnv((camera: Camera, resArray) => {
9+
const [_, __, dirtTexture] = resArray;
10+
const scene = camera.scene;
11+
12+
camera.enablePostProcess = true;
13+
camera.enableHDR = false;
14+
// @ts-ignore
15+
const bloomEffect = scene._postProcessManager._bloomEffect;
16+
// @ts-ignore
17+
const tonemappingEffect = scene._postProcessManager._tonemappingEffect;
18+
19+
bloomEffect.enabled = true;
20+
tonemappingEffect.enabled = true;
21+
22+
bloomEffect.threshold = 0.5;
23+
bloomEffect.dirtTexture = dirtTexture;
24+
tonemappingEffect.mode = TonemappingMode.Neutral;
25+
});

e2e/config.ts

+17
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,22 @@ export const E2E_CONFIG = {
180180
caseFileName: "particleRenderer-dream",
181181
threshold: 0.3
182182
}
183+
},
184+
PostProcess: {
185+
HDRBloomACES: {
186+
category: "PostProcess",
187+
caseFileName: "postProcess-HDR-bloom-ACES",
188+
threshold: 0.2
189+
},
190+
HDRBloomNeutral: {
191+
category: "PostProcess",
192+
caseFileName: "postProcess-HDR-bloom-neutral",
193+
threshold: 0.2
194+
},
195+
LDRBloomNeutral: {
196+
category: "PostProcess",
197+
caseFileName: "postProcess-LDR-bloom-neutral",
198+
threshold: 0.2
199+
}
183200
}
184201
};
Loading
Loading
Loading

packages/core/src/BasicResources.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import { TextureFormat } from "./texture/enums/TextureFormat";
1717
* @internal
1818
*/
1919
export class BasicResources {
20+
/**
21+
* Use triangle to blit texture, ref: https://michaldrobot.com/2014/04/01/gcn-execution-patterns-in-full-screen-passes/ .
22+
*/
2023
readonly blitMesh: ModelMesh;
2124
readonly flipYBlitMesh: ModelMesh;
2225
readonly blitMaterial: Material;
@@ -30,16 +33,14 @@ export class BasicResources {
3033
// prettier-ignore
3134
const vertices = new Float32Array([
3235
-1, -1, 0, 1, // left-bottom
33-
1, -1, 1, 1, // right-bottom
34-
-1, 1, 0, 0, // left-top
35-
1, 1, 1, 0]); // right-top
36+
3, -1, 2, 1, // right-bottom
37+
-1, 3, 0, -1 ]); // left-top
3638

3739
// prettier-ignore
3840
const flipYVertices = new Float32Array([
39-
1, -1, 1, 0, // right-bottom
41+
3, -1, 2, 0, // right-bottom
4042
-1, -1, 0, 0, // left-bottom
41-
1, 1, 1, 1, // right-top
42-
-1, 1, 0, 1]); // left-top
43+
-1, 3, 0, 2]); // left-top
4344

4445
const blitMaterial = new Material(engine, Shader.find("blit"));
4546
blitMaterial._addReferCount(1);
@@ -80,7 +81,7 @@ export class BasicResources {
8081
mesh._addReferCount(1);
8182
mesh.setVertexElements([new VertexElement("POSITION_UV", 0, VertexElementFormat.Vector4, 0)]);
8283
mesh.setVertexBufferBinding(new Buffer(engine, BufferBindFlag.VertexBuffer, vertices, BufferUsage.Static), 16);
83-
mesh.addSubMesh(0, 4, MeshTopology.TriangleStrip);
84+
mesh.addSubMesh(0, 3, MeshTopology.Triangles);
8485
return mesh;
8586
}
8687

packages/core/src/Camera.ts

+48-15
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { BasicRenderPipeline } from "./RenderPipeline/BasicRenderPipeline";
88
import { PipelineUtils } from "./RenderPipeline/PipelineUtils";
99
import { Transform } from "./Transform";
1010
import { VirtualCamera } from "./VirtualCamera";
11-
import { Logger } from "./base";
11+
import { GLCapabilityType, Logger } from "./base";
1212
import { deepClone, ignoreClone } from "./clone/CloneManager";
1313
import { CameraClearFlags } from "./enums/CameraClearFlags";
1414
import { CameraType } from "./enums/CameraType";
@@ -21,6 +21,7 @@ import { ShaderMacroCollection } from "./shader/ShaderMacroCollection";
2121
import { ShaderProperty } from "./shader/ShaderProperty";
2222
import { ShaderTagKey } from "./shader/ShaderTagKey";
2323
import { ShaderDataGroup } from "./shader/enums/ShaderDataGroup";
24+
import { TextureFormat } from "./texture";
2425
import { RenderTarget } from "./texture/RenderTarget";
2526
import { TextureCubeFace } from "./texture/enums/TextureCubeFace";
2627

@@ -118,6 +119,8 @@ export class Camera extends Component {
118119
private _renderTarget: RenderTarget = null;
119120
private _depthBufferParams: Vector4 = new Vector4();
120121
private _opaqueTextureEnabled: boolean = false;
122+
private _enableHDR = false;
123+
private _enablePostProcess = false;
121124

122125
@ignoreClone
123126
private _frustumChangeFlag: BoolUpdateFlag;
@@ -141,7 +144,6 @@ export class Camera extends Component {
141144
* If enabled, the opaque texture can be accessed in the shader using `camera_OpaqueTexture`.
142145
*
143146
* @defaultValue `false`
144-
*
145147
* @remarks If enabled, the `independentCanvasEnabled` property will be forced to be true.
146148
*/
147149
get opaqueTextureEnabled(): boolean {
@@ -161,11 +163,11 @@ export class Camera extends Component {
161163
* @remarks If true, the msaa in viewport can turn or off independently by `msaaSamples` property.
162164
*/
163165
get independentCanvasEnabled(): boolean {
164-
if (this._renderTarget) {
165-
return false;
166+
if (this.enableHDR || (this.enablePostProcess && this.scene._postProcessManager.hasActiveEffect)) {
167+
return true;
166168
}
167169

168-
return this._forceUseInternalCanvas();
170+
return this.opaqueTextureEnabled && !this._renderTarget;
169171
}
170172

171173
/**
@@ -356,15 +358,40 @@ export class Camera extends Component {
356358

357359
/**
358360
* Whether to enable HDR.
359-
* @todo When render pipeline modification
361+
* @defaultValue `false`
362+
* @remarks If enabled, the `independentCanvasEnabled` property will be forced to be true.
360363
*/
361364
get enableHDR(): boolean {
362-
console.log("not implementation");
363-
return false;
365+
return this._enableHDR;
364366
}
365367

366368
set enableHDR(value: boolean) {
367-
console.log("not implementation");
369+
if (this.enableHDR !== value) {
370+
const rhi = this.engine._hardwareRenderer;
371+
const supportHDR = rhi.isWebGL2 || rhi.canIUse(GLCapabilityType.textureHalfFloat);
372+
if (value && !supportHDR) {
373+
Logger.warn("Can't enable HDR in this device.");
374+
return;
375+
}
376+
this._enableHDR = value;
377+
this._checkMainCanvasAntialiasWaste();
378+
}
379+
}
380+
381+
/**
382+
* Whether to enable post process.
383+
* @defaultValue `false`
384+
* @remarks If enabled, the `independentCanvasEnabled` property will be forced to be true.
385+
*/
386+
get enablePostProcess(): boolean {
387+
return this._enablePostProcess;
388+
}
389+
390+
set enablePostProcess(value: boolean) {
391+
if (this._enablePostProcess !== value) {
392+
this._enablePostProcess = value;
393+
this._checkMainCanvasAntialiasWaste();
394+
}
368395
}
369396

370397
/**
@@ -380,7 +407,6 @@ export class Camera extends Component {
380407
value && this._addResourceReferCount(value, 1);
381408
this._renderTarget = value;
382409
this._onPixelViewportChanged();
383-
this._checkMainCanvasAntialiasWaste();
384410
}
385411
}
386412

@@ -662,6 +688,17 @@ export class Camera extends Component {
662688
this.scene._componentsManager.removeCamera(this);
663689
}
664690

691+
/**
692+
* @internal
693+
*/
694+
_getInternalColorTextureFormat(): TextureFormat {
695+
return this._enableHDR
696+
? this.engine._hardwareRenderer.isWebGL2
697+
? TextureFormat.R11G11B10_UFloat
698+
: TextureFormat.R16G16B16A16
699+
: TextureFormat.R8G8B8A8;
700+
}
701+
665702
/**
666703
* @internal
667704
* @inheritdoc
@@ -768,10 +805,6 @@ export class Camera extends Component {
768805
return this._inverseProjectionMatrix;
769806
}
770807

771-
private _forceUseInternalCanvas(): boolean {
772-
return this.opaqueTextureEnabled;
773-
}
774-
775808
@ignoreClone
776809
private _onPixelViewportChanged(): void {
777810
this._updatePixelViewport();
@@ -781,7 +814,7 @@ export class Camera extends Component {
781814

782815
private _checkMainCanvasAntialiasWaste(): void {
783816
if (this.independentCanvasEnabled && Vector4.equals(this._viewport, PipelineUtils.defaultViewport)) {
784-
console.warn(
817+
Logger.warn(
785818
"Camera use independent canvas and viewport cover the whole screen, it is recommended to disable antialias, depth and stencil to save memory when create engine."
786819
);
787820
}

0 commit comments

Comments
 (0)