threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GBufferRenderPass.ts 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import {Color, Material, WebGLMultipleRenderTargets, WebGLRenderTarget} from 'three'
  2. import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js'
  3. import {IPassID, IPipelinePass} from './Pass'
  4. import {ICamera, IMaterial, IRenderManager, IScene, IWebGLRenderer, PhysicalMaterial} from '../core'
  5. import {uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js'
  6. @uiFolderContainer<GBufferRenderPass>((c)=>c.passId + ' Render Pass')
  7. export class GBufferRenderPass<TP extends IPassID=IPassID, T extends WebGLMultipleRenderTargets | WebGLRenderTarget=WebGLMultipleRenderTargets | WebGLRenderTarget> extends RenderPass implements IPipelinePass<TP> { // todo: extend from jittered?
  8. readonly isGBufferRenderPass = true
  9. uiConfig: UiObjectConfig
  10. @uiToggle('Enabled') enabled = true
  11. scene?: IScene
  12. before?: IPassID[]
  13. after?: IPassID[]
  14. required?: IPassID[]
  15. constructor(public readonly passId: TP, public target: T, material: Material, clearColor: Color = new Color(1, 1, 1), clearAlpha = 1) {
  16. super(undefined, undefined, material, clearColor, clearAlpha)
  17. }
  18. private _transparentMats = new Set<IMaterial>()
  19. private _transmissiveMats = new Set<[IMaterial, number]>()
  20. preprocessMaterial = (material: IMaterial, renderToGBuffer?: boolean) => {
  21. renderToGBuffer = renderToGBuffer ?? material.userData.renderToGBuffer
  22. if (material.userData.pluginsDisabled) renderToGBuffer = false
  23. if (
  24. material.transparent && (renderToGBuffer || material.opacity > 0.99) || // transparent and render to gbuffer
  25. !material.transparent && !material.transmission && renderToGBuffer === false // opaque and dont render to gbuffer
  26. ) {
  27. this._transparentMats.add(material)
  28. material.transparent = !material.transparent
  29. // material.needsUpdate = true
  30. }
  31. if (
  32. material.transmission &&
  33. Math.abs(material.transmission || 0) > 0 && renderToGBuffer // transmission and render to gbuffer
  34. ) {
  35. this._transmissiveMats.add([material, material.transmission])
  36. material.transmission = 0
  37. // material.needsUpdate = true
  38. }
  39. }
  40. /**
  41. * Renders to {@link target}
  42. * @param renderer
  43. * @param _ - this is ignored
  44. * @param _1 - this is ignored
  45. * @param deltaTime
  46. * @param maskActive
  47. */
  48. render(renderer: IWebGLRenderer, _?: WebGLRenderTarget|WebGLMultipleRenderTargets|null, _1?: WebGLRenderTarget|WebGLMultipleRenderTargets, deltaTime?: number, maskActive?: boolean) {
  49. if (!this.scene || !this.camera) return
  50. const t = renderer.getRenderTarget()
  51. const activeCubeFace = renderer.getActiveCubeFace()
  52. const activeMipLevel = renderer.getActiveMipmapLevel()
  53. this.scene.traverse(({material}) => {
  54. if (!material) return
  55. if (Array.isArray(material)) material.forEach((m)=>this.preprocessMaterial(m))
  56. else this.preprocessMaterial(material)
  57. })
  58. // todo; copy double sided, check with post processing
  59. renderer.renderWithModes({
  60. shadowMapRender: false,
  61. backgroundRender: false,
  62. opaqueRender: true,
  63. transparentRender: false,
  64. transmissionRender: false,
  65. mainRenderPass: false,
  66. }, ()=> super.render(renderer, null, this.target, deltaTime as any, maskActive as any)) // here this.target is the write-buffer, variable writeBuffer is ignored
  67. this._transparentMats.forEach(m => m.transparent = !m.transparent)
  68. this._transparentMats.clear()
  69. this._transmissiveMats.forEach(([m, tr]: [PhysicalMaterial, number]) => m.transmission = tr)
  70. this._transmissiveMats.clear()
  71. renderer.setRenderTarget(t, activeCubeFace, activeMipLevel)
  72. }
  73. beforeRender(scene: IScene, camera: ICamera, _: IRenderManager): void {
  74. this.scene = scene
  75. this.camera = camera
  76. }
  77. }