threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. ---
  2. prev:
  3. text: 'Plugin System'
  4. link: './plugin-system'
  5. next:
  6. text: 'Screen Pass'
  7. link: './screen-pass'
  8. ---
  9. # Screen Pass - Extensions and Shaders
  10. The `ScreenPass` is the final rendering stage in Threepipe that outputs the rendered scene to the screen or a render target. It provides multiple ways to customize the final image through custom shaders, material extensions, and shader snippets.
  11. ## Overview
  12. The Screen Pass renders the final scene by processing the diffuse and transparent render targets. It supports:
  13. - Custom fragment shaders
  14. - Shader snippets for simple modifications
  15. - Material extensions for complex modifications
  16. - Built-in features like tonemapping, background clipping, and transparency handling
  17. Check out the [ScreenPass.glsl](https://github.com/repalash/threepipe/blob/master/src/postprocessing/ScreenPass.glsl) for the default fragment shader code used in the screen pass.
  18. Let's explore how to customize the screen pass using different methods to achieve a color tint effect as an example.
  19. <iframe src="https://threepipe.org/examples/screen-pass-extension-plugin/" style="width:100%;min-height:600px;border:none;" loading="lazy" title="Screen Pass Extension Example"></iframe>
  20. ## Basic Screen Shader
  21. The simplest way to customize the screen pass is by providing a shader snippet as a string:
  22. ```typescript
  23. const viewer = new ThreeViewer({
  24. canvas: document.getElementById('canvas'),
  25. screenShader: `
  26. // add a basic red tint
  27. diffuseColor *= vec4(1.0, 0.0, 0.0, 1.0);
  28. `
  29. })
  30. ```
  31. This snippet is inserted at the `#glMarker` position in the default screen shader and can modify the `diffuseColor` variable which contains the final pixel color.
  32. **Live Example:** [Basic Screen Shader](https://threepipe.org/examples/#screen-shader/)
  33. ## Advanced Screen Shader with Parameters
  34. For more complex modifications, you can provide shader parameters and functions:
  35. ```typescript
  36. const viewer = new ThreeViewer({
  37. canvas: document.getElementById('canvas'),
  38. screenShader: {
  39. pars: ` // this is added before the main function
  40. uniform vec3 tintColor;
  41. vec4 applyTint(vec4 color) {
  42. return vec4(color.rgb * tintColor, color.a);
  43. }
  44. `,
  45. main: ` // this is added inside the main function
  46. diffuseColor = applyTint(diffuseColor);
  47. `
  48. }
  49. })
  50. // Add the uniform to the screen pass material
  51. viewer.renderManager.screenPass.material.uniforms.tintColor = {
  52. value: new Color(0, 0, 1) // blue tint
  53. }
  54. ```
  55. **Live Example:** [Advanced Screen Shader](https://threepipe.org/examples/#screen-shader-advanced/)
  56. ## Custom Screen Shader Material
  57. For complete control, you can provide a full shader material configuration:
  58. ```typescript
  59. const viewer = new ThreeViewer({
  60. canvas: document.getElementById('canvas'),
  61. tonemap: true,
  62. screenShader: new ExtendedShaderMaterial({
  63. ...CopyShader,
  64. // Custom fragment shader
  65. fragmentShader: `
  66. #include <packing>
  67. varying vec2 vUv;
  68. uniform vec3 tintColor;
  69. void main() {
  70. vec4 diffuseColor = tDiffuseTexelToLinear (texture2D(tDiffuse, vUv));
  71. #glMarker
  72. diffuseColor.rgb *= tintColor;
  73. gl_FragColor = diffuseColor;
  74. #include <colorspace_fragment>
  75. }
  76. `,
  77. uniforms: {
  78. tDiffuse: {value: null},
  79. tTransparent: {value: null},
  80. tintColor: {value: new Color(0, 1, 0)},
  81. },
  82. transparent: true,
  83. blending: NoBlending,
  84. side: FrontSide,
  85. }, ['tDiffuse', 'tTransparent'])
  86. })
  87. ```
  88. **Live Example:** [Custom Screen Shader Material](https://threepipe.org/examples/#screen-shader-material/)
  89. ## The #glMarker System
  90. The `#glMarker` is a special placeholder in the screen shader that allows plugins and extensions to inject their own code. This enables:
  91. 1. **Plugin Integration**: Plugins like tonemap, vignette, and film grain can modify the final image
  92. 2. **Extension Points**: Multiple extensions can modify the same shader without conflicts
  93. 3. **Shader Composition**: Complex effects can be built by combining multiple extensions
  94. When using custom screen shaders, include `#glMarker` to ensure compatibility with plugins:
  95. ```glsl
  96. void main() {
  97. vec4 diffuseColor = tDiffuseTexelToLinear (texture2D(tDiffuse, vUv));
  98. #glMarker // Plugin injection point
  99. // Your custom modifications
  100. diffuseColor.rgb *= tintColor;
  101. gl_FragColor = diffuseColor;
  102. }
  103. ```
  104. ## Screen Pass Material Extensions
  105. Material extensions provide the most flexible way to modify the screen pass. They allow you to:
  106. - Add custom uniforms, defines
  107. - Inject/modify shader code
  108. - Hook into render events
  109. ```typescript
  110. const extension = {
  111. extraUniforms: {
  112. tintColor: {value: new Color(0, 1, 1)} // cyan tint
  113. },
  114. parsFragmentSnippet: ` // added before main function
  115. uniform vec3 tintColor;
  116. vec4 applyTint(vec4 color) {
  117. return vec4(color.rgb * tintColor, color.a);
  118. }
  119. `,
  120. shaderExtender: (shader, material, renderer) => {
  121. console.log('Patching shader')
  122. shader.fragmentShader = shaderReplaceString(
  123. shader.fragmentShader,
  124. '#glMarker',
  125. `diffuseColor = applyTint(diffuseColor);`,
  126. {prepend: true} // prepend to existing #glMarker content
  127. )
  128. },
  129. priority: 100, // execution order
  130. isCompatible: (material) => material.isShaderMaterial,
  131. computeCacheKey: (material) => 'tint-extension'
  132. }
  133. // Register the extension
  134. viewer.renderManager.screenPass.material.registerMaterialExtensions([extension])
  135. ```
  136. **Live Example:** [Screen Pass Extension](https://threepipe.org/examples/#screen-pass-extension/)
  137. ## Screen Pass Extension Plugins
  138. For more complex effects that need UI configuration and serialization, you can create a custom screen pass extension plugin using `AScreenPassExtensionPlugin`. This base class provides automatic UI generation, serialization, and integration with the plugin system.
  139. ```typescript
  140. import {
  141. AScreenPassExtensionPlugin,
  142. Color,
  143. glsl,
  144. onChange,
  145. serialize,
  146. uiColor,
  147. uiFolderContainer,
  148. uiSlider,
  149. uiToggle,
  150. uniform,
  151. } from 'threepipe'
  152. @uiFolderContainer('Custom Tint Extension')
  153. export class CustomScreenPassExtensionPlugin extends AScreenPassExtensionPlugin {
  154. static readonly PluginType = 'CustomTint'
  155. // Define uniforms that will be available in the shader
  156. readonly extraUniforms = {
  157. tintIntensity: {value: 1},
  158. tintColor: {value: new Color(0xff0000)},
  159. } as const
  160. // Plugin properties with UI decorators
  161. @onChange(CustomScreenPassExtensionPlugin.prototype.setDirty)
  162. @uiToggle('Enable')
  163. @serialize() enabled: boolean = true
  164. @uiSlider('Intensity', [0.1, 4], 0.01)
  165. @uniform({propKey: 'tintIntensity'}) // Links to extraUniforms
  166. @serialize() intensity = 1
  167. @uiColor('Color')
  168. @uniform({propKey: 'tintColor'})
  169. @serialize('tintColor') color = new Color(0xff0000)
  170. /**
  171. * Priority determines the order of extension application
  172. * Lower values = applied later (after other extensions)
  173. */
  174. priority = -50
  175. /**
  176. * Add shader code before the main function
  177. * Use glsl`` template literal for syntax highlighting
  178. */
  179. parsFragmentSnippet = () => {
  180. if (this.isDisabled()) return ''
  181. return glsl`
  182. uniform float tintIntensity;
  183. uniform vec3 tintColor;
  184. vec4 ApplyTint(vec4 color) {
  185. return vec4(color.rgb * tintColor * tintIntensity, color.a);
  186. }
  187. `
  188. }
  189. /**
  190. * Shader code to inject at the #glMarker position
  191. */
  192. protected _shaderPatch = 'diffuseColor = ApplyTint(diffuseColor);'
  193. constructor(enabled = true) {
  194. super()
  195. this.enabled = enabled
  196. }
  197. }
  198. // Register the plugin
  199. const viewer = new ThreeViewer({
  200. canvas: document.getElementById('canvas'),
  201. plugins: [CustomScreenPassExtensionPlugin],
  202. })
  203. ```
  204. ### Key Features of Extension Plugins:
  205. 1. **Automatic UI Generation**: UI decorators create controls automatically
  206. 2. **Serialization**: Properties are saved/loaded with `@serialize()`
  207. 3. **Uniform Binding**: `@uniform()` decorator links properties to shader uniforms
  208. 4. **Change Detection**: `@onChange()` triggers updates when properties change
  209. 5. **Priority System**: Control the order of extension application
  210. 6. **Conditional Logic**: Use `isDisabled()` to conditionally apply effects
  211. ### Extension Plugin Methods:
  212. - `parsFragmentSnippet()`: Add code before the main function
  213. - `_shaderPatch`: Code to inject at #glMarker (can also be a function)
  214. - `isDisabled()`: Check if the extension should be applied
  215. - `setDirty()`: Mark the material for recompilation
  216. **Live Example:** [Screen Pass Extension Plugin](https://threepipe.org/examples/#screen-pass-extension-plugin/)
  217. ## Built-in Features
  218. ### Background Clipping
  219. Control background rendering with the `clipBackground` option:
  220. ```typescript
  221. // Enable background clipping
  222. viewer.renderManager.screenPass.clipBackground = true
  223. // Force background clipping (overrides the above which is also in the UI)
  224. viewer.renderManager.screenPass.clipBackgroundForce = true
  225. ```
  226. ### Output Color Space
  227. Configure the output color space for the final render:
  228. ```typescript
  229. import { SRGBColorSpace, LinearSRGBColorSpace } from 'threepipe'
  230. viewer.renderManager.screenPass.outputColorSpace = SRGBColorSpace
  231. ```
  232. ## Available Variables
  233. When writing custom screen shaders, these variables are available:
  234. - `diffuseColor`: The final pixel color (vec4)
  235. - `tDiffuse`: Main render target texture (sampler2D)
  236. - `vUv`: UV coordinates (vec2)
  237. - `transparentColor`: Transparent objects color (vec4)
  238. - `tTransparent`: Transparent render target texture (sampler2D)
  239. ### Working with G-Buffer
  240. When using the GBufferPlugin, additional variables become available:
  241. ::: details GBuffer Snippet
  242. ```glsl
  243. #ifdef HAS_GBUFFER
  244. float depth = getDepth(vUv);
  245. bool isBackground = depth > 0.99 && transparentColor.a < 0.001;
  246. #endif
  247. ```
  248. :::
  249. ```glsl
  250. // Use depth information for effects
  251. diffuseColor.rgb = mix(diffuseColor.rgb, fogColor.rgb, depth);
  252. ```
  253. ## Best Practices
  254. 1. **Always include #glMarker** in custom shaders to maintain plugin compatibility
  255. 2. **Use material extensions** for complex modifications that need to interact with other plugins
  256. 3. **Test with different plugins** to ensure compatibility
  257. 4. **Consider performance** when adding complex shader operations
  258. 5. **Use appropriate uniforms** instead of hardcoded values for dynamic effects
  259. ## Integration with Plugins
  260. Many built-in plugins extend the screen pass:
  261. - **TonemapPlugin**: Adds tone mapping to the final image
  262. - **VignettePlugin**: Adds vignette effect
  263. - **FilmGrainPlugin**: Adds film grain texture
  264. - **ChromaticAberrationPlugin**: Adds chromatic aberration
  265. These plugins use the material extension system to inject their effects at the `#glMarker` position, allowing them to work together seamlessly.