| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- import {IPipelinePass} from './Pass'
- import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js'
- import {
- Color,
- HalfFloatType,
- LinearFilter,
- Material,
- NoColorSpace,
- RGBAFormat,
- Texture,
- UnsignedByteType,
- WebGLRenderTarget,
- } from 'three'
- import {generateUiConfig, UiObjectConfig, uiToggle} from 'uiconfig.js'
- import {serialize} from 'ts-browser-helpers'
- import {GenericBlendTexturePass} from './GenericBlendTexturePass'
- import {IRenderTarget} from '../rendering'
- import {ICamera, IRenderManager, IScene, IWebGLRenderer} from '../core'
- import {ViewerRenderManager} from '../viewer'
-
- export class ExtendedRenderPass extends RenderPass implements IPipelinePass<'render'> {
- readonly isExtendedRenderPass = true
-
- @uiToggle('Enabled') @serialize() enabled = true
- readonly passId = 'render'
-
- private _blendPass: GenericBlendTexturePass
- readonly renderManager: ViewerRenderManager
- private _doTransmissionFix = true
- blurTransmissionTarget = true
- preserveTransparentTarget = false
- private _transparentTarget?: IRenderTarget
-
- get transparentTarget(): IRenderTarget {
- if (!this._transparentTarget) {
- const msaa = this.renderManager.msaa
- this._transparentTarget = this.renderManager.getTempTarget({
- sizeMultiplier: 1,
- samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0,
- colorSpace: NoColorSpace,
- type: this.renderManager.renderer.extensions.has('EXT_color_buffer_half_float') ? HalfFloatType : UnsignedByteType,
- format: RGBAFormat,
- minFilter: LinearFilter,
- magFilter: LinearFilter,
- depthBuffer: false,
- })
- }
- return this._transparentTarget
- }
-
- private _releaseTransparentTarget() {
- if (this._transparentTarget)
- this.renderManager.releaseTempTarget(this._transparentTarget)
- this._transparentTarget = undefined
- }
-
- readonly preserveOpaqueTarget = false
- private _opaqueTarget?: WebGLRenderTarget
-
- get opaqueTarget(): WebGLRenderTarget {
- if (!this._opaqueTarget) {
- const composerTarget = this.renderManager.composerTarget as WebGLRenderTarget
- const msaa = this.renderManager.msaa
- this._opaqueTarget = this.renderManager.getTempTarget({
- sizeMultiplier: 1,
- samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0,
- colorSpace: composerTarget.texture.colorSpace,
- type: this.renderManager.rgbm ? UnsignedByteType : HalfFloatType,
- format: composerTarget.texture.format,
- minFilter: composerTarget.texture.minFilter,
- magFilter: composerTarget.texture.magFilter,
- depthBuffer: composerTarget.depthBuffer,
- generateMipmaps: composerTarget.texture.generateMipmaps,
- })
- // console.log(this._opaqueTarget.samples)
- }
- return this._opaqueTarget
- }
- private _releaseOpaqueTarget() {
- if (this._opaqueTarget)
- this.renderManager.releaseTempTarget(this._opaqueTarget)
- this._opaqueTarget = undefined
- }
-
- constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) {
- super(undefined, undefined, overrideMaterial, clearColor, clearAlpha)
- this.renderManager = renderManager
- this._blendPass = new GenericBlendTexturePass({}, 'c = vec4(a.rgb * (1. - b.a) + b.rgb * b.a, 1.);', '', undefined, renderManager.maxHDRIntensity)
- this.setDirty = this.setDirty.bind(this)
- }
-
- // names are incorrect. We read from `writeBuffer` and write to `readBuffer`. same in super class
- render(renderer: IWebGLRenderer, writeBuffer?: WebGLRenderTarget<Texture|Texture[]>|null, readBuffer?: WebGLRenderTarget<Texture|Texture[]>, deltaTime?: number, maskActive?: boolean) {
- if (!this.enabled) return
- let needsSwap = false
-
- renderer.userData.mainRenderPass = true
- if (!this._doTransmissionFix && !this.renderManager.rgbm) {
- super.render(renderer, writeBuffer || null, readBuffer, deltaTime, maskActive)
- this.needsSwap = needsSwap
- renderer.userData.mainRenderPass = undefined
- return
- }
-
- const ud = renderer.userData
- if (!ud) console.error('threejs is not patched. Use the @repalash/three.js-modded to this functionality.')
-
- const useGBufferDepth = (this.renderManager.zPrepass || !this.renderManager.depthBuffer) && this.renderManager.gbufferTarget
- let depthRenderBuffer: WebGLRenderbuffer | undefined = undefined
-
- if (useGBufferDepth) {
-
- const gbuffer = this.renderManager.gbufferTarget
- if (gbuffer) {
- const renderBufferProps = renderer.properties.get(gbuffer)
- depthRenderBuffer = renderBufferProps.__webglDepthRenderbuffer || renderBufferProps.__webglDepthbuffer
- }
- if (!depthRenderBuffer) {
- console.warn('No depth/gbuffer present for zPrepass.')
- }
-
- }
-
- const lastReadBuffer = readBuffer
-
- // if msaa we need to create a new multi sampled target to render to
-
- // todo
- readBuffer = this.renderManager.msaa ? this.opaqueTarget : readBuffer
- // readBuffer = this.opaqueTarget
- // if(readBuffer?.samples !== gbuffer?.samples)
- // console.error('ExtendedRenderPass - readBuffer and gbuffer samples are not same', readBuffer?.samples, gbuffer?.samples)
-
- let renderFn = ()=> {
- super.render(renderer, null, readBuffer, deltaTime, maskActive, depthRenderBuffer) // read is write in super.render (RenderPass)
- }
-
- if (!this.renderManager.rgbm) {
-
- // Opaque + Transparent
- {
-
- const curClear = this.clear
- const curClearDepth = renderer.autoClearDepth
- renderer.autoClearDepth = !useGBufferDepth
- this.clear = true
-
- renderer.renderWithModes({
- shadowMapRender: true,
- backgroundRender: true,
- opaqueRender: true,
- transparentRender: true,
- transmissionRender: false,
- }, renderFn)
-
- this.clear = curClear
- renderer.autoClearDepth = curClearDepth
-
- }
-
- // Transmissive
- {
- const source = !readBuffer ? undefined : Array.isArray(readBuffer.texture) ? readBuffer.texture[0] : readBuffer.texture
- // todo: first check if any transmissive object is there to use this buffer
- this.renderManager.blit(writeBuffer, {clear: true, source})
- // viewer.renderer.blit(writeBuffer.texture as any, readBuffer as any, {})
- // super.render(renderer, undefined as any, writeBuffer, deltaTime, maskActive); // copy read to write buffer
-
- const curClear = this.clear
- this.clear = false
-
- // don't need this clear is already false
- // const curClearDepth = renderer.autoClearDepth
- // renderer.autoClearDepth = false
-
- ud.transmissionRenderTarget = writeBuffer
- ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa target. its fine now because writeBuffer is never multi sampled
-
- renderer.renderWithModes({
- shadowMapRender: false,
- backgroundRender: false,
- opaqueRender: false,
- transparentRender: false,
- transmissionRender: true,
- }, renderFn)
-
- ud.blurTransmissionTarget = undefined
- ud.transmissionRenderTarget = undefined
-
- // renderer.autoClearDepth = curClearDepth
-
- this.clear = curClear
- }
-
- needsSwap = false
-
- } else if (this.renderManager.rgbm) {
-
- needsSwap = false
-
- const renderToScreen = this.renderToScreen
- if (renderToScreen && !writeBuffer) {
- console.error('ExtendedRenderPass: renderToScreen is true but writeBuffer is not set, which is required for rgbm')
- }
- this.renderToScreen = false // for super RenderPass.render
-
- if (renderer.info && !renderer.info.autoReset)
- throw 'renderer.info.autoReset must be true' // it is required to check if any object is rendered in the scene, also frame count is maintained separately in the render manager, use that.
-
-
- // Opaque
- {
- const curClearDepth = renderer.autoClearDepth
- renderer.autoClearDepth = !useGBufferDepth
-
- renderer.renderWithModes({
- shadowMapRender: true,
- backgroundRender: true,
- opaqueRender: true,
- transparentRender: false,
- transmissionRender: false,
- }, renderFn) // render to readBuffer
-
- renderer.autoClearDepth = curClearDepth
-
- }
-
- if (!useGBufferDepth && readBuffer) {
- const renderBufferProps2 = renderer.properties.get(readBuffer)
- depthRenderBuffer = renderBufferProps2.__webglDepthRenderbuffer || renderBufferProps2.__webglDepthbuffer
- }
-
- // readBuffer has data
-
- renderFn = ()=> {
- super.render(renderer, null, this.transparentTarget as any, deltaTime, maskActive, depthRenderBuffer)
- }
-
- // Transparent
- {
- const curClear = this.clear
- const curClearDepth = renderer.autoClearDepth
- renderer.autoClearDepth = false
- this.clear = true
-
- renderer.renderWithModes({
- shadowMapRender: false,
- backgroundRender: false,
- opaqueRender: false,
- transparentRender: true,
- transmissionRender: false,
- }, renderFn) // render to transparentTarget
-
- this.clear = curClear
- renderer.autoClearDepth = curClearDepth
- }
-
- if (!renderer.info || renderer.info.render.calls > 0) {
-
- // writeBuffer = transparentTarget + readBuffer
- this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture
- this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive)
- needsSwap = true // writeBuffer has the data now.
-
- }
-
- // if needsSwap, writeBuffer has data, else readBuffer
-
- // Transmission
- {
- const curClear = this.clear
- this.clear = false // it is cleared in transparent pass above even if no object is rendered
-
- // const curClearDepth = renderer.autoClearDepth
- // renderer.autoClearDepth = false
-
- // if needsSwap, writeBuffer has current data, else readBuffer
- ud.transmissionRenderTarget = needsSwap ? writeBuffer : readBuffer
- ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa
-
- renderer.renderWithModes({
- shadowMapRender: false,
- backgroundRender: false,
- opaqueRender: false,
- transparentRender: false,
- transmissionRender: true,
- }, renderFn) // render to transparentTarget
-
- ud.blurTransmissionTarget = undefined
- ud.transmissionRenderTarget = undefined
-
- // renderer.autoClearDepth = curClearDepth
-
- this.clear = curClear
- }
-
- // console.log(renderer.info.render.calls)
- if (!renderer.info || renderer.info.render.calls > 0) {
-
- // console.log('missive blit', renderer.info.render.frame)
-
- // writeBuffer = transparentTarget + readBuffer. opaque will overwrite opaque pixels again
- this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture
- this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive)
- needsSwap = true // writeBuffer has the data now.
-
- }
-
- // if needsSwap, writeBuffer has data, else readBuffer
-
- if (renderToScreen) {
- this.renderToScreen = true
- const tex = needsSwap ? writeBuffer?.texture : readBuffer?.texture
- const source = Array.isArray(tex) ? tex[0] : tex
- source && this.renderManager.blit(undefined, {
- source, respectColorSpace: true,
- })
- // needsSwap = false
- }
-
- }
-
- // todo no need to do this if renderToScreen is true
- // resolve msaa
- if (!needsSwap && lastReadBuffer !== readBuffer && readBuffer) {
- // copy from readBuffer to lastReadBuffer
- const source = Array.isArray(readBuffer.texture) ? readBuffer.texture[0] : readBuffer.texture
- source && this.renderManager.blit(lastReadBuffer, {
- source: source, clear: true,
- })
- readBuffer = lastReadBuffer
- }
-
- if (!this.preserveTransparentTarget)
- this._releaseTransparentTarget()
- if (!this.preserveOpaqueTarget)
- this._releaseOpaqueTarget()
-
- this.needsSwap = needsSwap
- renderer.userData.mainRenderPass = undefined
- }
-
-
- public onDirty: (()=>void)[] = []
- dispose() {
- this._releaseTransparentTarget()
- this.onDirty = []
- this.scene = undefined
- this.camera = undefined
- super.dispose?.()
- }
-
- setDirty() {
- this.onDirty.forEach(v=>v())
- }
-
- beforeRender(scene: IScene, camera: ICamera, _: IRenderManager): void {
- this.scene = scene
- this.camera = camera
- }
-
- uiConfig: UiObjectConfig = {
- label: 'Render Pass',
- type: 'folder',
- children: generateUiConfig(this),
- }
-
-
- // legacy
-
- /**
- * @deprecated renamed to {@link isExtendedRenderPass}
- */
- get isRenderPass2() {
- console.error('isRenderPass2 is deprecated, use isExtendedRenderPass instead')
- return true
- }
-
- }
-
- /**
- * @deprecated renamed to {@link ExtendedRenderPass}
- */
- export class RenderPass2 extends ExtendedRenderPass {
- constructor(...args: ConstructorParameters<typeof ExtendedRenderPass>) {
- console.error('RenderPass2 is deprecated, use ExtendedRenderPass instead')
- super(...args)
- }
- }
|