Skip to content

Commit bdc6485

Browse files
authored
Nodes: Add BloomNode. (#28903)
* Nodes: Add `BloomNode`. * E2E: Update screenshot. * BloomNode: Fix reference.
1 parent 6ec8898 commit bdc6485

File tree

5 files changed

+519
-0
lines changed

5 files changed

+519
-0
lines changed

examples/files.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@
374374
"webgpu_postprocessing_afterimage",
375375
"webgpu_postprocessing_anamorphic",
376376
"webgpu_postprocessing_ao",
377+
"webgpu_postprocessing_bloom",
377378
"webgpu_postprocessing_dof",
378379
"webgpu_postprocessing_pixel",
379380
"webgpu_postprocessing_fxaa",
26.8 KB
Loading
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>three.js webgpu - postprocessing - bloom</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7+
<link type="text/css" rel="stylesheet" href="main.css">
8+
<style>
9+
#info > * {
10+
max-width: 650px;
11+
margin-left: auto;
12+
margin-right: auto;
13+
}
14+
</style>
15+
</head>
16+
<body>
17+
18+
<div id="container"></div>
19+
20+
<div id="info">
21+
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Bloom pass by <a href="http://eduperiment.com" target="_blank" rel="noopener">Prashant Sharma</a> and <a href="https://clara.io" target="_blank" rel="noopener">Ben Houston</a>
22+
<br/>
23+
Model: <a href="https://blog.sketchfab.com/art-spotlight-primary-ion-drive/" target="_blank" rel="noopener">Primary Ion Drive</a> by
24+
<a href="http://mjmurdock.com/" target="_blank" rel="noopener">Mike Murdock</a>, CC Attribution.
25+
</div>
26+
27+
<script type="importmap">
28+
{
29+
"imports": {
30+
"three": "../build/three.webgpu.js",
31+
"three/tsl": "../build/three.webgpu.js",
32+
"three/addons/": "./jsm/"
33+
}
34+
}
35+
</script>
36+
37+
<script type="module">
38+
39+
import * as THREE from 'three';
40+
import { pass, bloom } from 'three/tsl';
41+
42+
import Stats from 'three/addons/libs/stats.module.js';
43+
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
44+
45+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
46+
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
47+
48+
49+
let camera, stats;
50+
let postProcessing, renderer, mixer, clock;
51+
52+
const params = {
53+
threshold: 0,
54+
strength: 1,
55+
radius: 0,
56+
exposure: 1
57+
};
58+
59+
init();
60+
61+
async function init() {
62+
63+
const container = document.getElementById( 'container' );
64+
65+
clock = new THREE.Clock();
66+
67+
const scene = new THREE.Scene();
68+
69+
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
70+
camera.position.set( - 5, 2.5, - 3.5 );
71+
scene.add( camera );
72+
73+
scene.add( new THREE.AmbientLight( 0xcccccc ) );
74+
75+
const pointLight = new THREE.PointLight( 0xffffff, 100 );
76+
camera.add( pointLight );
77+
78+
const loader = new GLTFLoader();
79+
const gltf = await loader.loadAsync( 'models/gltf/PrimaryIonDrive.glb' );
80+
81+
const model = gltf.scene;
82+
scene.add( model );
83+
84+
mixer = new THREE.AnimationMixer( model );
85+
const clip = gltf.animations[ 0 ];
86+
mixer.clipAction( clip.optimize() ).play();
87+
88+
//
89+
90+
renderer = new THREE.WebGPURenderer( { antialias: true } );
91+
renderer.setPixelRatio( window.devicePixelRatio );
92+
renderer.setSize( window.innerWidth, window.innerHeight );
93+
renderer.setAnimationLoop( animate );
94+
renderer.toneMapping = THREE.ReinhardToneMapping;
95+
container.appendChild( renderer.domElement );
96+
97+
//
98+
99+
postProcessing = new THREE.PostProcessing( renderer );
100+
101+
const scenePass = pass( scene, camera );
102+
const scenePassColor = scenePass.getTextureNode( 'output' );
103+
104+
const bloomPass = bloom( scenePassColor );
105+
106+
postProcessing.outputNode = scenePassColor.add( bloomPass );
107+
108+
//
109+
110+
stats = new Stats();
111+
container.appendChild( stats.dom );
112+
113+
//
114+
115+
const controls = new OrbitControls( camera, renderer.domElement );
116+
controls.maxPolarAngle = Math.PI * 0.5;
117+
controls.minDistance = 3;
118+
controls.maxDistance = 8;
119+
120+
//
121+
122+
const gui = new GUI();
123+
124+
const bloomFolder = gui.addFolder( 'bloom' );
125+
126+
bloomFolder.add( params, 'threshold', 0.0, 1.0 ).onChange( function ( value ) {
127+
128+
bloomPass.threshold.value = value;
129+
130+
} );
131+
132+
bloomFolder.add( params, 'strength', 0.0, 3.0 ).onChange( function ( value ) {
133+
134+
bloomPass.strength.value = value;
135+
136+
} );
137+
138+
gui.add( params, 'radius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
139+
140+
bloomPass.radius.value = value;
141+
142+
} );
143+
144+
const toneMappingFolder = gui.addFolder( 'tone mapping' );
145+
146+
toneMappingFolder.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {
147+
148+
renderer.toneMappingExposure = Math.pow( value, 4.0 );
149+
150+
} );
151+
152+
window.addEventListener( 'resize', onWindowResize );
153+
154+
}
155+
156+
function onWindowResize() {
157+
158+
const width = window.innerWidth;
159+
const height = window.innerHeight;
160+
161+
camera.aspect = width / height;
162+
camera.updateProjectionMatrix();
163+
164+
renderer.setSize( width, height );
165+
166+
}
167+
168+
function animate() {
169+
170+
const delta = clock.getDelta();
171+
172+
mixer.update( delta );
173+
174+
postProcessing.render();
175+
176+
stats.update();
177+
178+
}
179+
180+
</script>
181+
182+
</body>
183+
184+
</html>

src/nodes/Nodes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ export { default as Lut3DNode, lut3D } from './display/Lut3DNode.js';
137137
export { default as GTAONode, ao } from './display/GTAONode.js';
138138
export { default as DenoiseNode, denoise } from './display/DenoiseNode.js';
139139
export { default as FXAANode, fxaa } from './display/FXAANode.js';
140+
export { default as BloomNode, bloom } from './display/BloomNode.js';
140141
export { default as RenderOutputNode, renderOutput } from './display/RenderOutputNode.js';
141142
export { default as PixelationPassNode, pixelationPass } from './display/PixelationPassNode.js';
142143

0 commit comments

Comments
 (0)