webgpu-postprocessing.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <!DOCTYPE html><html lang="en"><head>
  2. <meta charset="utf-8">
  3. <title>Post-Processing with WebGPURenderer</title>
  4. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  5. <meta name="twitter:card" content="summary_large_image">
  6. <meta name="twitter:site" content="@threejs">
  7. <meta name="twitter:title" content="Three.js – Post-Processing with WebGPURenderer">
  8. <meta property="og:image" content="https://threejs.org/files/share.png">
  9. <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
  10. <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
  11. <link rel="stylesheet" href="../resources/lesson.css">
  12. <link rel="stylesheet" href="../resources/lang.css">
  13. <script type="importmap">
  14. {
  15. "imports": {
  16. "three": "../../build/three.module.js"
  17. }
  18. }
  19. </script>
  20. </head>
  21. <body>
  22. <div class="container">
  23. <div class="lesson-title">
  24. <h1>Post-Processing with WebGPURenderer</h1>
  25. </div>
  26. <div class="lesson">
  27. <div class="lesson-main">
  28. <p>
  29. `WebGPURenderer` comes with a brand-new component for post-processing. This article shows how the new system
  30. works and provides some basic guidelines about the usage.
  31. </p>
  32. <h2>Overview</h2>
  33. <p>
  34. The previous post-processing for `WebGLRenderer` had many conceptual issues. Making use of Multiple Render Targets
  35. (MRT) was cumbersome due to the limited support in the renderer and there was no automatic pass/effect combination
  36. to improve the overall performance.
  37. </p>
  38. <p>
  39. The new post-processing stack for `WebGPURenderer` was designed to support these use cases right from the beginning.
  40. </p>
  41. <ul>
  42. <li>
  43. `WebGPURenderer` and `PostProcessing` come with full, built-in MRT support.
  44. </li>
  45. <li>
  46. The system combines effects if possible which reduces the overall number of render passes.
  47. </li>
  48. <li>
  49. The effect chain is expressed as a node composition which allows a more flexible effect setup.
  50. </li>
  51. </ul>
  52. <p>
  53. Let's find out how to integrate `PostProcessing` in three.js applications.
  54. </p>
  55. <h2>Basics</h2>
  56. <p>
  57. First, please read the instructions in the guide about <a href="webgpurenderer">WebGPURenderer</a> to correctly configure your
  58. imports. After that, you can create an instance of the post-processing module like so.
  59. </p>
  60. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  61. const postProcessing = new THREE.PostProcessing( renderer );
  62. </pre>
  63. <p>
  64. The instance of `PostProcessing` replaces the previous instance of `EffectComposer`. To make sure you actually
  65. use the output of the module, you have to update your animation loop like so:
  66. </p>
  67. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  68. - renderer.render( scene, camera );
  69. + postProcessing.render();
  70. </pre>
  71. <p>
  72. Many post-processing setups start with a so called "scene pass" or "beauty pass" that represents the image of you rendered scene.
  73. This image should be subsequently enhanced by different effects like Bloom, Depth-of-Field or SSR. Start by importing the `pass()` TSL
  74. function from the TSL namespace and use it to create the pass.
  75. </p>
  76. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  77. import { pass } from 'three/tsl';
  78. // in your init routine
  79. const scenePass = pass( scene, camera );
  80. </pre>
  81. <p>
  82. The basic idea of the node system is to represent materials or post-processing effects as node compositions. To configure a basic
  83. Dotscreen and RGB shift effect, you create effect nodes with TSL functions and compose them together.
  84. </p>
  85. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  86. import { pass } from 'three/tsl';
  87. + import { dotScreen } from 'three/addons/tsl/display/DotScreenNode.js';
  88. + import { rgbShift } from 'three/addons/tsl/display/RGBShiftNode.js';
  89. // in your init routine
  90. const scenePass = pass( scene, camera );
  91. + const dotScreenPass = dotScreen( scenePass );
  92. + const rgbShiftPass = rgbShift( dotScreenPass );
  93. </pre>
  94. <p>
  95. When you are done, you can simply assign the final node to the `PostProcessing` instance.
  96. </p>
  97. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  98. postProcessing.outputNode = rgbShiftPass;
  99. </pre>
  100. <h2>Tone Mapping and Color Spaces</h2>
  101. <p>
  102. When using post-processing, tone mapping and color space conversion are automatically applied at the end
  103. of your effect chain. Sometimes you want full control over how and when these steps are executed though.
  104. For example if you want to apply FXAA with `FXAANode` or color grading with `Lut3DNode`, you can disable automatic tone
  105. mapping and color space conversion and apply it via `renderOutput()` by yourself.
  106. </p>
  107. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  108. import { pass, renderOutput } from 'three/tsl';
  109. import { fxaa } from 'three/addons/tsl/display/FXAANode.js';
  110. // in your init routine
  111. const postProcessing = new THREE.PostProcessing( renderer );
  112. postProcessing.outputColorTransform = false; // disable default output color transform
  113. const scenePass = pass( scene, camera );
  114. const outputPass = renderOutput( scenePass ); // apply tone mapping and color space conversion here
  115. // FXAA must be computed in sRGB color space
  116. const fxaaPass = fxaa( outputPass );
  117. postProcessing.outputNode = fxaaPass;
  118. </pre>
  119. <p>
  120. It is not mandatory to use `renderOutput()`, you can also implement a custom tone mapping and color space conversion
  121. based on your requirements.
  122. </p>
  123. <h2>MRT</h2>
  124. <p>
  125. The new post-processing stack has built-in Multiple Render Targets (MRT) support which is crucial for more advanced
  126. setups. MRT allows you to produce multiple outputs in a single render pass. So for example when rendering your scene
  127. with TRAA, you need below setup to prepare the inputs for the anti-aliasing.
  128. </p>
  129. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  130. import { pass, mrt, output, velocity } from 'three/tsl';
  131. // in your init routine
  132. const scenePass = pass( scene, camera );
  133. scenePass.setMRT( mrt( {
  134. output: output,
  135. velocity: velocity
  136. } ) );
  137. </pre>
  138. <p>
  139. The configuration object you assign to the `mrt()` TSL function describes the different outputs of the pass. In this case,
  140. we save the default output (the scene's beauty) and scene's velocity since we want to setup a TRAA. If you also require
  141. the scene's depth, there is no need to configure it as a MRT output. You get it for free in your default output pass if
  142. you request it in your app. If you know want to use these outputs in subsequent effects, you can query them as texture nodes.
  143. </p>
  144. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  145. import { traa } from 'three/addons/tsl/display/TRAANode.js';
  146. // in your init routine
  147. const scenePassColor = scenePass.getTextureNode( 'output' );
  148. const scenePassDepth = scenePass.getTextureNode( 'depth' );
  149. const scenePassVelocity = scenePass.getTextureNode( 'velocity' );
  150. const traaPass = traa( scenePassColor, scenePassDepth, scenePassVelocity, camera );
  151. postProcessing.outputNode = traaPass;
  152. </pre>
  153. <p>
  154. The MRT configuration varies depending on your setup. There are many different TSL objects like `output`, `velocity`,
  155. `normalView` or `emissive` than you can use to save per-fragment data in MRT attachments. To improve performance and avoid
  156. hitting memory restrictions, it's important to pack and optimize your data in complex MRT setups. By default all attachments
  157. are RGBA16 (Half-Float) in precision which is not necessary for all types of data. As an example, below code queries the
  158. `diffuseColor` attachment and sets its format to RGBA8 which cuts down the memory and bandwidth by half.
  159. </p>
  160. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  161. const diffuseTexture = scenePass.getTexture( 'diffuseColor' );
  162. diffuseTexture.type = THREE.UnsignedByteType;
  163. </pre>
  164. <p>
  165. Below setup for Scree-Space Reflections (SSR) converts the default FP16 normals into RGBA8 colors and packs metalness/roughness
  166. into a single attachment. The usage of the `sample()` TSL functions allows to implement custom unpacking. In this instance, it
  167. converts the color back to a (normalized) direction vector.
  168. </p>
  169. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">
  170. scenePass.setMRT( mrt( {
  171. output: output,
  172. normal: directionToColor( normalView ),
  173. metalrough: vec2( metalness, roughness )
  174. } ) );
  175. // use RGBA8 instead of RGBA16
  176. const normalTexture = scenePass.getTexture( 'normal' );
  177. normalTexture.type = THREE.UnsignedByteType;
  178. const metalRoughTexture = scenePass.getTexture( 'metalrough' );
  179. metalRoughTexture.type = THREE.UnsignedByteType;
  180. // custom unpacking. use the resulting "sceneNormal" instead of "scenePassNormal"
  181. // in subsequent effects
  182. const sceneNormal = sample( ( uv ) => {
  183. return colorToDirection( scenePassNormal.sample( uv ) );
  184. } );
  185. </pre>
  186. <p>
  187. We want to further improve the packing/unpacking features in the future to offer more ways to pack/unpack MRT data. In the meanwhile,
  188. please have a look at the <a href="https://threejs.org/examples/?q=webgpu%20postprocessing" target="_blank">official examples</a> to
  189. get an overview about the existing effects and setups.
  190. </p>
  191. </div>
  192. </div>
  193. </div>
  194. <script src="../resources/prettify.js"></script>
  195. <script src="../resources/lesson.js"></script>
  196. </body>
  197. </html>
粤ICP备19079148号