webgl_postprocessing_fxaa.html 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js WebGL - postprocessing - FXAA</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. body {
  10. background-color: #fff;
  11. color: #222;
  12. }
  13. a {
  14. color: #08f;
  15. }
  16. #container {
  17. position: absolute;
  18. top: 70px;
  19. width: 100%;
  20. bottom: 0px;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div id="info">
  26. <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - postprocessing - FXAA<br />
  27. Left: No FXAA, Right: FXAA
  28. </div>
  29. <div id="container">
  30. </div>
  31. <script type="importmap">
  32. {
  33. "imports": {
  34. "three": "../build/three.module.js",
  35. "three/addons/": "./jsm/"
  36. }
  37. }
  38. </script>
  39. <script type="module">
  40. import * as THREE from 'three';
  41. import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
  42. import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
  43. import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
  44. import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
  45. import { FXAAShader } from 'three/addons/shaders/FXAAShader.js';
  46. let camera, scene, renderer, clock, group, container;
  47. let composer1, composer2, fxaaPass;
  48. init();
  49. function init() {
  50. container = document.getElementById( 'container' );
  51. camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 2000 );
  52. camera.position.z = 500;
  53. scene = new THREE.Scene();
  54. clock = new THREE.Clock();
  55. //
  56. const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d );
  57. hemiLight.position.set( 0, 1000, 0 );
  58. scene.add( hemiLight );
  59. const dirLight = new THREE.DirectionalLight( 0xffffff, 3 );
  60. dirLight.position.set( - 3000, 1000, - 1000 );
  61. scene.add( dirLight );
  62. //
  63. group = new THREE.Group();
  64. const geometry = new THREE.TetrahedronGeometry( 10 );
  65. const material = new THREE.MeshStandardMaterial( { color: 0xf73232, flatShading: true } );
  66. for ( let i = 0; i < 100; i ++ ) {
  67. const mesh = new THREE.Mesh( geometry, material );
  68. mesh.position.x = Math.random() * 500 - 250;
  69. mesh.position.y = Math.random() * 500 - 250;
  70. mesh.position.z = Math.random() * 500 - 250;
  71. mesh.scale.setScalar( Math.random() * 2 + 1 );
  72. mesh.rotation.x = Math.random() * Math.PI;
  73. mesh.rotation.y = Math.random() * Math.PI;
  74. mesh.rotation.z = Math.random() * Math.PI;
  75. group.add( mesh );
  76. }
  77. scene.add( group );
  78. //
  79. renderer = new THREE.WebGLRenderer();
  80. renderer.setPixelRatio( window.devicePixelRatio );
  81. renderer.setSize( container.offsetWidth, container.offsetHeight );
  82. renderer.setAnimationLoop( animate );
  83. renderer.autoClear = false;
  84. container.appendChild( renderer.domElement );
  85. //
  86. const renderPass = new RenderPass( scene, camera );
  87. renderPass.clearAlpha = 0;
  88. //
  89. fxaaPass = new ShaderPass( FXAAShader );
  90. const outputPass = new OutputPass();
  91. composer1 = new EffectComposer( renderer );
  92. composer1.addPass( renderPass );
  93. composer1.addPass( outputPass );
  94. //
  95. const pixelRatio = renderer.getPixelRatio();
  96. fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( container.offsetWidth * pixelRatio );
  97. fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( container.offsetHeight * pixelRatio );
  98. composer2 = new EffectComposer( renderer );
  99. composer2.addPass( renderPass );
  100. composer2.addPass( outputPass );
  101. // FXAA is engineered to be applied towards the end of engine post processing after conversion to low dynamic range and conversion to the sRGB color space for display.
  102. composer2.addPass( fxaaPass );
  103. //
  104. window.addEventListener( 'resize', onWindowResize );
  105. }
  106. function onWindowResize() {
  107. camera.aspect = container.offsetWidth / container.offsetHeight;
  108. camera.updateProjectionMatrix();
  109. renderer.setSize( container.offsetWidth, container.offsetHeight );
  110. composer1.setSize( container.offsetWidth, container.offsetHeight );
  111. composer2.setSize( container.offsetWidth, container.offsetHeight );
  112. const pixelRatio = renderer.getPixelRatio();
  113. fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( container.offsetWidth * pixelRatio );
  114. fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( container.offsetHeight * pixelRatio );
  115. }
  116. function animate() {
  117. const halfWidth = container.offsetWidth / 2;
  118. group.rotation.y += clock.getDelta() * 0.1;
  119. renderer.setScissorTest( true );
  120. renderer.setScissor( 0, 0, halfWidth - 1, container.offsetHeight );
  121. composer1.render();
  122. renderer.setScissor( halfWidth, 0, halfWidth, container.offsetHeight );
  123. composer2.render();
  124. renderer.setScissorTest( false );
  125. }
  126. </script>
  127. </body>
  128. </html>