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

ScreenPass.ts 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import {ExtendedShaderPass} from './ExtendedShaderPass'
  2. import {
  3. ColorSpace,
  4. FrontSide,
  5. NoBlending,
  6. ShaderMaterialParameters,
  7. SRGBColorSpace,
  8. WebGLMultipleRenderTargets,
  9. WebGLRenderTarget,
  10. } from 'three'
  11. import {ICamera, IRenderManager, IScene, IWebGLRenderer, ShaderMaterial2} from '../core'
  12. import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js'
  13. import {IPassID, IPipelinePass} from './Pass'
  14. import {uiDropdown, uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js'
  15. import {ViewerRenderManager} from '../viewer'
  16. import {matDefineBool, threeConstMappings} from '../three'
  17. import ScreenPassShader from './ScreenPass.glsl'
  18. import {shaderReplaceString} from '../utils'
  19. export type TViewerScreenShaderFrag = string | [string, string] | {pars?: string, main: string}
  20. export type TViewerScreenShader = TViewerScreenShaderFrag | ShaderMaterialParameters | ShaderMaterial2
  21. @uiFolderContainer('Screen Pass')
  22. export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> {
  23. uiConfig!: UiObjectConfig
  24. readonly passId = 'screen'
  25. after: IPassID[] = ['render']
  26. required: IPassID[] = ['render']
  27. constructor(shader: TViewerScreenShader = '', ...textureID: string[]) {
  28. super(
  29. (<any>shader)?.fragmentShader || (<ShaderMaterial2>shader)?.isShaderMaterial ? <ShaderMaterialParameters|ShaderMaterial2>shader :
  30. makeScreenShader(shader),
  31. ...textureID.length ? textureID : ['tDiffuse', 'tTransparent'])
  32. this.material.addEventListener('materialUpdate', this.setDirty)
  33. }
  34. /**
  35. * Output Color Space
  36. * Note: this is ignored when renderToScreen is false (it will take the color space of the render target)
  37. */
  38. @uiDropdown('Output Color Space', threeConstMappings.ColorSpace.uiConfig, (t: ScreenPass)=>({onChange: t.setDirty}))
  39. outputColorSpace: ColorSpace = SRGBColorSpace
  40. private _lastReadBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget
  41. render(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | null, readBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget, deltaTime?: number, maskActive?: boolean) {
  42. const colorSpace = renderer.outputColorSpace
  43. if (!writeBuffer || this.renderToScreen) renderer.outputColorSpace = this.outputColorSpace
  44. // else console.warn('ScreenPass: outputColorSpace is ignored when renderToScreen is false')
  45. super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive)
  46. this._lastReadBuffer = readBuffer
  47. renderer.outputColorSpace = colorSpace
  48. }
  49. reRender(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | null, deltaTime?: number, maskActive?: boolean) {
  50. if (this._lastReadBuffer) this.render(renderer, writeBuffer, this._lastReadBuffer, deltaTime, maskActive)
  51. }
  52. private _needsReRender = false
  53. onPostFrame(renderManager: IRenderManager) {
  54. if (!this._needsReRender) return
  55. this._needsReRender = false
  56. this.reRender(renderManager.renderer)
  57. if (this.clipBackground && !(renderManager as ViewerRenderManager).gbufferTarget) {
  58. // todo warn only when rgbm
  59. console.warn('ScreenPass: clipBackground set to true but no gbufferTarget set. Try adding GBufferPlugin.')
  60. }
  61. }
  62. dispose() {
  63. this._lastReadBuffer = undefined
  64. super.dispose()
  65. }
  66. /**
  67. * Force clip background. If this is `true` {@link clipBackground} is overridden.
  68. * This happens when scene.background and scene.backgroundColor are both null.
  69. * This is set in {@link ViewerRenderManager.render}.
  70. */
  71. @matDefineBool('CLIP_BACKGROUND_FORCE', undefined, undefined, ScreenPass.prototype.setDirty, true)
  72. clipBackgroundForce = false
  73. // todo: this is not serialized anymore?
  74. @matDefineBool('CLIP_BACKGROUND', undefined, undefined, ScreenPass.prototype.setDirty)
  75. @uiToggle() clipBackground = false
  76. beforeRender(_: IScene, _1: ICamera, renderManager: ViewerRenderManager) {
  77. this.material.uniforms.tTransparent.value = renderManager.renderPass.preserveTransparentTarget ? renderManager.renderPass.transparentTarget?.texture || null : null
  78. this.material.defines.HAS_TRANSPARENT_TARGET = this.material.uniforms.tTransparent.value ? 1 : undefined
  79. if (!this.material.defines.HAS_TRANSPARENT_TARGET) delete this.material.defines.HAS_TRANSPARENT_TARGET
  80. }
  81. setDirty() {
  82. super.setDirty()
  83. this._needsReRender = true
  84. }
  85. }
  86. function makeScreenShader(shader: string | [string, string] | {pars?: string; main: string} | ShaderMaterialParameters | ShaderMaterial2) {
  87. return {
  88. ...CopyShader,
  89. fragmentShader:
  90. shaderReplaceString(shaderReplaceString(ScreenPassShader,
  91. 'void main()', (Array.isArray(shader) ? shader[0] : (<any>shader)?.pars || '') + '\n', {prepend: true}),
  92. '#glMarker', (Array.isArray(shader) ? shader[1] : typeof shader === 'string' ? shader : (shader as any)?.main || '') + '\n', {prepend: true}),
  93. uniforms: {
  94. tDiffuse: {value: null},
  95. tTransparent: {value: null},
  96. },
  97. transparent: true,
  98. blending: NoBlending,
  99. side: FrontSide,
  100. } as ShaderMaterialParameters
  101. }