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

GBufferRenderPass.ts 3.7KB

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. /**
  17. * Renders to {@link target}
  18. * @param renderer
  19. * @param _ - this is ignored
  20. * @param _1 - this is ignored
  21. * @param deltaTime
  22. * @param maskActive
  23. */
  24. render(renderer: IWebGLRenderer, _?: WebGLRenderTarget|WebGLMultipleRenderTargets|null, _1?: WebGLRenderTarget|WebGLMultipleRenderTargets, deltaTime?: number, maskActive?: boolean) {
  25. if (!this.scene || !this.camera) return
  26. const t = renderer.getRenderTarget()
  27. const activeCubeFace = renderer.getActiveCubeFace()
  28. const activeMipLevel = renderer.getActiveMipmapLevel()
  29. const preprocessMaterial = (material: IMaterial) => {
  30. const renderToGBuffer = material.userData.renderToGBuffer === undefined ? material.userData.renderToDepth : material.userData.renderToGBuffer
  31. if (
  32. material.transparent && material.userData.renderToDepth || // transparent and render to gbuffer
  33. !material.transparent && !material.transmission && renderToGBuffer === false // opaque and dont render to gbuffer
  34. ) {
  35. this._transparentMats.add(material)
  36. material.transparent = !material.transparent
  37. // material.needsUpdate = true
  38. }
  39. if (
  40. material.transmission &&
  41. Math.abs(material.transmission || 0) > 0 && renderToGBuffer // transmission and render to gbuffer
  42. ) {
  43. this._transmissiveMats.add([material, material.transmission])
  44. material.transmission = 0
  45. // material.needsUpdate = true
  46. }
  47. }
  48. this.scene.traverse(({material}) => {
  49. if (!material) return
  50. if (Array.isArray(material)) material.forEach(preprocessMaterial)
  51. else 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. }