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.6KB

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