webgl_postprocessing_unreal_bloom.html 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - postprocessing - unreal 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. <div id="container"></div>
  18. <div id="info">
  19. <a href="http://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>
  20. <p>
  21. This Bloom Pass is inspired by the bloom pass of Unreal Engine. It creates a mip map chain of bloom textures and blurs them
  22. with different radii. Because of the weighted combination of mips, and since larger blurs are done on higher mips, this bloom
  23. is better in quality and performance.
  24. </p>
  25. Model: <a href="https://blog.sketchfab.com/art-spotlight-primary-ion-drive/" target="_blank" rel="noopener">Primary Ion Drive</a> by
  26. <a href="http://mjmurdock.com/" target="_blank" rel="noopener">Mike Murdock</a>, CC Attribution.
  27. </div>
  28. <script type="module">
  29. import * as THREE from '../build/three.module.js';
  30. import Stats from './jsm/libs/stats.module.js';
  31. import { GUI } from './jsm/libs/dat.gui.module.js';
  32. import { OrbitControls } from './jsm/controls/OrbitControls.js';
  33. import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
  34. import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
  35. import { RenderPass } from './jsm/postprocessing/RenderPass.js';
  36. import { UnrealBloomPass } from './jsm/postprocessing/UnrealBloomPass.js';
  37. var scene, camera, controls, pointLight, stats;
  38. var composer, renderer, mixer;
  39. var params = {
  40. exposure: 1,
  41. bloomStrength: 1.5,
  42. bloomThreshold: 0,
  43. bloomRadius: 0
  44. };
  45. var clock = new THREE.Clock();
  46. var container = document.getElementById( 'container' );
  47. stats = new Stats();
  48. container.appendChild( stats.dom );
  49. renderer = new THREE.WebGLRenderer( { antialias: true } );
  50. renderer.setPixelRatio( window.devicePixelRatio );
  51. renderer.setSize( window.innerWidth, window.innerHeight );
  52. renderer.toneMapping = THREE.ReinhardToneMapping;
  53. container.appendChild( renderer.domElement );
  54. scene = new THREE.Scene();
  55. camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
  56. camera.position.set( - 5, 2.5, - 3.5 );
  57. scene.add( camera );
  58. controls = new OrbitControls( camera, renderer.domElement );
  59. controls.maxPolarAngle = Math.PI * 0.5;
  60. controls.minDistance = 1;
  61. controls.maxDistance = 10;
  62. scene.add( new THREE.AmbientLight( 0x404040 ) );
  63. pointLight = new THREE.PointLight( 0xffffff, 1 );
  64. camera.add( pointLight );
  65. var renderScene = new RenderPass( scene, camera );
  66. var bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
  67. bloomPass.threshold = params.bloomThreshold;
  68. bloomPass.strength = params.bloomStrength;
  69. bloomPass.radius = params.bloomRadius;
  70. composer = new EffectComposer( renderer );
  71. composer.addPass( renderScene );
  72. composer.addPass( bloomPass );
  73. new GLTFLoader().load( 'models/gltf/PrimaryIonDrive.glb', function ( gltf ) {
  74. var model = gltf.scene;
  75. scene.add( model );
  76. // Mesh contains self-intersecting semi-transparent faces, which display
  77. // z-fighting unless depthWrite is disabled.
  78. var core = model.getObjectByName( 'geo1_HoloFillDark_0' );
  79. core.material.depthWrite = false;
  80. mixer = new THREE.AnimationMixer( model );
  81. var clip = gltf.animations[ 0 ];
  82. mixer.clipAction( clip.optimize() ).play();
  83. animate();
  84. } );
  85. var gui = new GUI();
  86. gui.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {
  87. renderer.toneMappingExposure = Math.pow( value, 4.0 );
  88. } );
  89. gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {
  90. bloomPass.threshold = Number( value );
  91. } );
  92. gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function ( value ) {
  93. bloomPass.strength = Number( value );
  94. } );
  95. gui.add( params, 'bloomRadius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
  96. bloomPass.radius = Number( value );
  97. } );
  98. window.onresize = function () {
  99. var width = window.innerWidth;
  100. var height = window.innerHeight;
  101. camera.aspect = width / height;
  102. camera.updateProjectionMatrix();
  103. renderer.setSize( width, height );
  104. composer.setSize( width, height );
  105. };
  106. function animate() {
  107. requestAnimationFrame( animate );
  108. const delta = clock.getDelta();
  109. mixer.update( delta );
  110. stats.update();
  111. composer.render();
  112. }
  113. </script>
  114. </body>
  115. </html>