| WebGLRenderTarget, | WebGLRenderTarget, | ||||
| } from 'three' | } from 'three' | ||||
| import {GBufferRenderPass} from '../../postprocessing' | import {GBufferRenderPass} from '../../postprocessing' | ||||
| import {ThreeViewer} from '../../viewer' | |||||
| import {ThreeViewer, ViewerRenderManager} from '../../viewer' | |||||
| import {MaterialExtension} from '../../materials' | import {MaterialExtension} from '../../materials' | ||||
| import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | ||||
| import {uiDropdown, uiFolderContainer, uiImage} from 'uiconfig.js' | import {uiDropdown, uiFolderContainer, uiImage} from 'uiconfig.js' | ||||
| export type DepthBufferPluginEventTypes = '' | export type DepthBufferPluginEventTypes = '' | ||||
| // type DepthBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | // type DepthBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | ||||
| export type DepthBufferPluginTarget = WebGLRenderTarget | export type DepthBufferPluginTarget = WebGLRenderTarget | ||||
| export type DepthBufferPluginPass = GBufferRenderPass<'depth', DepthBufferPluginTarget> | |||||
| export type DepthBufferPluginPass = GBufferRenderPass<'depth', DepthBufferPluginTarget|undefined> | |||||
| /** | /** | ||||
| * Depth Buffer Plugin | * Depth Buffer Plugin | ||||
| protected _createTarget(recreate = true) { | protected _createTarget(recreate = true) { | ||||
| if (!this._viewer) return | if (!this._viewer) return | ||||
| if (recreate) this._disposeTarget() | if (recreate) this._disposeTarget() | ||||
| const rm = this._viewer.renderManager | |||||
| if (!this.target) | if (!this.target) | ||||
| this.target = this._viewer.renderManager.createTarget<DepthBufferPluginTarget>( | this.target = this._viewer.renderManager.createTarget<DepthBufferPluginTarget>( | ||||
| { | { | ||||
| depthBuffer: true, | depthBuffer: true, | ||||
| samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer ? // requirement for zPrepass | |||||
| this._viewer.renderManager.composerTarget.samples || 0 : 0, | |||||
| samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer && rm.msaa ? // requirement for zPrepass | |||||
| typeof rm.msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : rm.msaa : 0, | |||||
| type: this.bufferType, | type: this.bufferType, | ||||
| // magFilter: NearestFilter, | // magFilter: NearestFilter, | ||||
| // minFilter: NearestFilter, | // minFilter: NearestFilter, | ||||
| this.texture = this.target.texture | this.texture = this.target.texture | ||||
| this.texture.name = 'depthBuffer' | this.texture.name = 'depthBuffer' | ||||
| if (this._pass) this._pass.target = this.target | |||||
| // if (this._pass) this._pass.target = this.target | |||||
| if (this.isPrimaryGBuffer) { | if (this.isPrimaryGBuffer) { | ||||
| this._viewer.renderManager.gbufferTarget = this.target | this._viewer.renderManager.gbufferTarget = this.target | ||||
| this._createTarget(true) | this._createTarget(true) | ||||
| if (!this.target) throw new Error('DepthBufferPlugin: target not created') | if (!this.target) throw new Error('DepthBufferPlugin: target not created') | ||||
| this.material.userData.isGBufferMaterial = true | this.material.userData.isGBufferMaterial = true | ||||
| const pass = new GBufferRenderPass(this.passId, this.target, this.material, new Color(0, 0, 0), 1) | |||||
| const pass = new GBufferRenderPass(this.passId, ()=>this.target, this.material, new Color(0, 0, 0), 1) | |||||
| const preprocessMaterial = pass.preprocessMaterial | const preprocessMaterial = pass.preprocessMaterial | ||||
| pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth) // if renderToDepth is undefined then renderToGbuffer is taken internally | pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth) // if renderToDepth is undefined then renderToGbuffer is taken internally | ||||
| pass.before = ['render'] | pass.before = ['render'] |
| WebGLRenderTarget, | WebGLRenderTarget, | ||||
| } from 'three' | } from 'three' | ||||
| import {GBufferRenderPass} from '../../postprocessing' | import {GBufferRenderPass} from '../../postprocessing' | ||||
| import {ThreeViewer} from '../../viewer' | |||||
| import {ThreeViewer, ViewerRenderManager} from '../../viewer' | |||||
| import {MaterialExtension, updateMaterialDefines} from '../../materials' | import {MaterialExtension, updateMaterialDefines} from '../../materials' | ||||
| import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | ||||
| import {uiFolderContainer, uiImage} from 'uiconfig.js' | import {uiFolderContainer, uiImage} from 'uiconfig.js' | ||||
| export type GBufferPluginEventTypes = '' | export type GBufferPluginEventTypes = '' | ||||
| export type GBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | export type GBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | ||||
| // export type GBufferPluginTarget = WebGLRenderTarget | // export type GBufferPluginTarget = WebGLRenderTarget | ||||
| export type GBufferPluginPass = GBufferRenderPass<'gbuffer', GBufferPluginTarget> | |||||
| export type GBufferPluginPass = GBufferRenderPass<'gbuffer', GBufferPluginTarget|undefined> | |||||
| export interface GBufferUpdaterContext { | export interface GBufferUpdaterContext { | ||||
| material: IMaterial, renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D | material: IMaterial, renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D | ||||
| // } | // } | ||||
| unpackExtension: MaterialExtension = { | unpackExtension: MaterialExtension = { | ||||
| /** | |||||
| * Use this in shader to get the snippet | |||||
| * ``` | |||||
| * // for gbuffer | |||||
| * #include <packing> | |||||
| * #define THREE_PACKING_INCLUDED | |||||
| * ``` | |||||
| * or if you don't need packing include | |||||
| * ``` | |||||
| * #include <gbuffer_unpack> | |||||
| * ``` | |||||
| * @param shader | |||||
| */ | |||||
| shaderExtender: (shader)=>{ | shaderExtender: (shader)=>{ | ||||
| const includes = ['gbuffer_unpack', 'packing'] as const | const includes = ['gbuffer_unpack', 'packing'] as const | ||||
| const include = includes.find(i=>shader.fragmentShader.includes(`#include <${i}>`)) | const include = includes.find(i=>shader.fragmentShader.includes(`#include <${i}>`)) | ||||
| if (recreateTarget) this._disposeTarget() | if (recreateTarget) this._disposeTarget() | ||||
| const useMultiple = this._viewer?.renderManager.isWebGL2 && this.renderFlagsBuffer | const useMultiple = this._viewer?.renderManager.isWebGL2 && this.renderFlagsBuffer | ||||
| if (!this.target) { | if (!this.target) { | ||||
| const rm = this._viewer.renderManager | |||||
| this.target = this._viewer.renderManager.createTarget<GBufferPluginTarget>( | this.target = this._viewer.renderManager.createTarget<GBufferPluginTarget>( | ||||
| { | { | ||||
| depthBuffer: true, | depthBuffer: true, | ||||
| samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer ? // requirement for zPrepass | |||||
| this._viewer.renderManager.composerTarget.samples || 0 : 0, | |||||
| samples: this._viewer.renderManager.zPrepass && this.isPrimaryGBuffer && rm.msaa ? // requirement for zPrepass | |||||
| typeof rm.msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : rm.msaa : 0, | |||||
| type: this.bufferType, | type: this.bufferType, | ||||
| textureCount: useMultiple ? 2 : 1, | textureCount: useMultiple ? 2 : 1, | ||||
| depthTexture: this.renderDepthTexture, | depthTexture: this.renderDepthTexture, | ||||
| }) | }) | ||||
| } | } | ||||
| if (this._pass) this._pass.target = this.target | |||||
| // if (this._pass) this._pass.target = this.target | |||||
| if (this.isPrimaryGBuffer) { | if (this.isPrimaryGBuffer) { | ||||
| this._viewer.renderManager.gbufferTarget = this.target | this._viewer.renderManager.gbufferTarget = this.target | ||||
| if (!this.target) throw new Error('GBufferPlugin: target not created') | if (!this.target) throw new Error('GBufferPlugin: target not created') | ||||
| if (!this.material) throw new Error('GBufferPlugin: material not created') | if (!this.material) throw new Error('GBufferPlugin: material not created') | ||||
| this.material.userData.isGBufferMaterial = true | this.material.userData.isGBufferMaterial = true | ||||
| const pass = new GBufferRenderPass(this.passId, this.target, this.material, new Color(1, 1, 1), 1) | |||||
| const pass = new GBufferRenderPass(this.passId, ()=>this.target, this.material, new Color(1, 1, 1), 1) | |||||
| const preprocessMaterial = pass.preprocessMaterial | const preprocessMaterial = pass.preprocessMaterial | ||||
| pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth) // if renderToDepth is undefined then renderToGbuffer is taken internally | pass.preprocessMaterial = (m) => preprocessMaterial(m, m.userData.renderToDepth) // if renderToDepth is undefined then renderToGbuffer is taken internally | ||||
| pass.before = ['render'] | pass.before = ['render'] |
| export type NormalBufferPluginEventTypes = '' | export type NormalBufferPluginEventTypes = '' | ||||
| // type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | // type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | ||||
| export type NormalBufferPluginTarget = WebGLRenderTarget | export type NormalBufferPluginTarget = WebGLRenderTarget | ||||
| export type NormalBufferPluginPass = GBufferRenderPass<'normal', NormalBufferPluginTarget> | |||||
| export type NormalBufferPluginPass = GBufferRenderPass<'normal', NormalBufferPluginTarget|undefined> | |||||
| /** | /** | ||||
| * Normal Buffer Plugin | * Normal Buffer Plugin | ||||
| * | * | ||||
| if (!this._viewer) return | if (!this._viewer) return | ||||
| if (recreate) this._disposeTarget() | if (recreate) this._disposeTarget() | ||||
| // const rm = this._viewer.renderManager | |||||
| if (!this.target) this.target = this._viewer.renderManager.createTarget<NormalBufferPluginTarget>( | if (!this.target) this.target = this._viewer.renderManager.createTarget<NormalBufferPluginTarget>( | ||||
| { | { | ||||
| depthBuffer: true, | depthBuffer: true, | ||||
| // samples: v.renderManager.composerTarget.samples || 0, | |||||
| // samples: rm.msaa ? typeof rm.msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : rm.msaa : 0, | |||||
| samples: 0, | samples: 0, | ||||
| type: this.bufferType, | type: this.bufferType, | ||||
| magFilter: NearestFilter, | magFilter: NearestFilter, | ||||
| this.texture = this.target.texture | this.texture = this.target.texture | ||||
| this.texture.name = 'normalBuffer' | this.texture.name = 'normalBuffer' | ||||
| if (this._pass) this._pass.target = this.target | |||||
| // if (this._pass) this._pass.target = this.target | |||||
| } | } | ||||
| protected _disposeTarget() { | protected _disposeTarget() { | ||||
| if (!this._viewer) return | if (!this._viewer) return | ||||
| this._createTarget(true) | this._createTarget(true) | ||||
| if (!this.target) throw new Error('NormalBufferPlugin: target not created') | if (!this.target) throw new Error('NormalBufferPlugin: target not created') | ||||
| this.material.userData.isGBufferMaterial = true | this.material.userData.isGBufferMaterial = true | ||||
| const pass = new GBufferRenderPass(this.passId, this.target, this.material, new Color(0, 0, 0), 1) | |||||
| const pass = new GBufferRenderPass(this.passId, ()=>this.target, this.material, new Color(0, 0, 0), 1) | |||||
| const preprocessMaterial = pass.preprocessMaterial | const preprocessMaterial = pass.preprocessMaterial | ||||
| pass.preprocessMaterial = (m) => preprocessMaterial(m, true) | pass.preprocessMaterial = (m) => preprocessMaterial(m, true) | ||||
| pass.before = ['render'] | pass.before = ['render'] |
| this.texture = this.target.texture | this.texture = this.target.texture | ||||
| this.texture.name = 'ssaoBuffer' | this.texture.name = 'ssaoBuffer' | ||||
| if (this._pass) this._pass.target = this.target | |||||
| // if (this._pass) this._pass.target = this.target | |||||
| } | } | ||||
| protected _disposeTarget() { | protected _disposeTarget() { | ||||
| if (!this._viewer.renderManager.gbufferTarget || !this._viewer.renderManager.gbufferUnpackExtension) | if (!this._viewer.renderManager.gbufferTarget || !this._viewer.renderManager.gbufferUnpackExtension) | ||||
| throw new Error('SSAOPlugin: GBuffer target not created. GBufferPlugin or DepthBufferPlugin is required.') | throw new Error('SSAOPlugin: GBuffer target not created. GBufferPlugin or DepthBufferPlugin is required.') | ||||
| this._createTarget(true) | this._createTarget(true) | ||||
| // todo: send target as a func, so it works when changed | |||||
| return new SSAOPluginPass(this.passId, this.target) | |||||
| return new SSAOPluginPass(this.passId, ()=>this.target) | |||||
| } | } | ||||
| onAdded(viewer: ThreeViewer) { | onAdded(viewer: ThreeViewer) { | ||||
| #include <simpleCameraHelpers> | #include <simpleCameraHelpers> | ||||
| `, | `, | ||||
| computeCacheKey: () => { | computeCacheKey: () => { | ||||
| return this.enabled ? '1' : '0' + getOrCall(this.target)?.texture?.colorSpace | |||||
| return (this.enabled ? '1' : '0') + getOrCall(this.target)?.texture?.colorSpace | |||||
| }, | }, | ||||
| uuid: SSAOPlugin.PluginType, | uuid: SSAOPlugin.PluginType, | ||||
| ...uiConfigMaterialExtension(this._getUiConfig.bind(this), SSAOPlugin.PluginType), | ...uiConfigMaterialExtension(this._getUiConfig.bind(this), SSAOPlugin.PluginType), |
| get transparentTarget(): IRenderTarget { | get transparentTarget(): IRenderTarget { | ||||
| if (!this._transparentTarget) { | if (!this._transparentTarget) { | ||||
| const msaa = this.renderManager.msaa | |||||
| this._transparentTarget = this.renderManager.getTempTarget({ | this._transparentTarget = this.renderManager.getTempTarget({ | ||||
| sizeMultiplier: 1, | sizeMultiplier: 1, | ||||
| samples: this.renderManager.composerTarget.samples || 0, | |||||
| samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0, | |||||
| colorSpace: NoColorSpace, | colorSpace: NoColorSpace, | ||||
| type: this.renderManager.renderer.extensions.has('EXT_color_buffer_half_float') ? HalfFloatType : UnsignedByteType, | type: this.renderManager.renderer.extensions.has('EXT_color_buffer_half_float') ? HalfFloatType : UnsignedByteType, | ||||
| format: RGBAFormat, | format: RGBAFormat, | ||||
| } | } | ||||
| return this._transparentTarget | return this._transparentTarget | ||||
| } | } | ||||
| private _releaseTransparentTarget() { | private _releaseTransparentTarget() { | ||||
| if (this._transparentTarget) | if (this._transparentTarget) | ||||
| this.renderManager.releaseTempTarget(this._transparentTarget) | this.renderManager.releaseTempTarget(this._transparentTarget) | ||||
| this._transparentTarget = undefined | 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) { | constructor(renderManager: ViewerRenderManager, overrideMaterial?: Material, clearColor = new Color(0, 0, 0), clearAlpha = 0) { | ||||
| super(undefined, undefined, overrideMaterial, clearColor, clearAlpha) | super(undefined, undefined, overrideMaterial, clearColor, clearAlpha) | ||||
| this.renderManager = renderManager | this.renderManager = renderManager | ||||
| this.setDirty = this.setDirty.bind(this) | 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?: WebGLMultipleRenderTargets|WebGLRenderTarget|null, readBuffer?: WebGLMultipleRenderTargets|WebGLRenderTarget, deltaTime?: number, maskActive?: boolean) { | render(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets|WebGLRenderTarget|null, readBuffer?: WebGLMultipleRenderTargets|WebGLRenderTarget, deltaTime?: number, maskActive?: boolean) { | ||||
| if (!this.enabled) return | if (!this.enabled) return | ||||
| let needsSwap = false | let needsSwap = false | ||||
| } | } | ||||
| const ud = renderer.userData | const ud = renderer.userData | ||||
| if (!ud) console.error('threejs is not patched?') | |||||
| 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 | const useGBufferDepth = (this.renderManager.zPrepass || !this.renderManager.depthBuffer) && this.renderManager.gbufferTarget | ||||
| let depthRenderBuffer: WebGLRenderbuffer | undefined = undefined | let depthRenderBuffer: WebGLRenderbuffer | undefined = undefined | ||||
| } | } | ||||
| 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 = ()=> { | let renderFn = ()=> { | ||||
| super.render(renderer, null, readBuffer, deltaTime, maskActive, depthRenderBuffer) // read is write in super.render (RenderPass) | super.render(renderer, null, readBuffer, deltaTime, maskActive, depthRenderBuffer) // read is write in super.render (RenderPass) | ||||
| } | } | ||||
| // renderer.autoClearDepth = false | // renderer.autoClearDepth = false | ||||
| ud.transmissionRenderTarget = writeBuffer | ud.transmissionRenderTarget = writeBuffer | ||||
| ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa | |||||
| 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({ | renderer.renderWithModes({ | ||||
| shadowMapRender: false, | shadowMapRender: false, | ||||
| opaqueRender: true, | opaqueRender: true, | ||||
| transparentRender: false, | transparentRender: false, | ||||
| transmissionRender: false, | transmissionRender: false, | ||||
| }, renderFn) | |||||
| }, renderFn) // render to readBuffer | |||||
| renderer.autoClearDepth = curClearDepth | renderer.autoClearDepth = curClearDepth | ||||
| const renderBufferProps2 = renderer.properties.get(readBuffer) | const renderBufferProps2 = renderer.properties.get(readBuffer) | ||||
| depthRenderBuffer = renderBufferProps2.__webglDepthRenderbuffer || renderBufferProps2.__webglDepthbuffer | depthRenderBuffer = renderBufferProps2.__webglDepthRenderbuffer || renderBufferProps2.__webglDepthbuffer | ||||
| } | } | ||||
| // readBuffer has data | |||||
| renderFn = ()=> { | renderFn = ()=> { | ||||
| super.render(renderer, null, this.transparentTarget as any, deltaTime, maskActive, depthRenderBuffer) | super.render(renderer, null, this.transparentTarget as any, deltaTime, maskActive, depthRenderBuffer) | ||||
| } | } | ||||
| opaqueRender: false, | opaqueRender: false, | ||||
| transparentRender: true, | transparentRender: true, | ||||
| transmissionRender: false, | transmissionRender: false, | ||||
| }, renderFn) | |||||
| }, renderFn) // render to transparentTarget | |||||
| this.clear = curClear | this.clear = curClear | ||||
| renderer.autoClearDepth = curClearDepth | renderer.autoClearDepth = curClearDepth | ||||
| if (!renderer.info || renderer.info.render.calls > 0) { | if (!renderer.info || renderer.info.render.calls > 0) { | ||||
| // writeBuffer = transparentTarget + readBuffer | |||||
| this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture | this._blendPass.uniforms.tDiffuse2.value = this.transparentTarget.texture | ||||
| this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | ||||
| needsSwap = true | |||||
| needsSwap = true // writeBuffer has the data now. | |||||
| } | } | ||||
| // if needsSwap, writeBuffer has data, else readBuffer | |||||
| // Transmission | // Transmission | ||||
| { | { | ||||
| const curClear = this.clear | const curClear = this.clear | ||||
| // const curClearDepth = renderer.autoClearDepth | // const curClearDepth = renderer.autoClearDepth | ||||
| // renderer.autoClearDepth = false | // renderer.autoClearDepth = false | ||||
| // if needsSwap, writeBuffer has current data, else readBuffer | |||||
| ud.transmissionRenderTarget = needsSwap ? writeBuffer : readBuffer | ud.transmissionRenderTarget = needsSwap ? writeBuffer : readBuffer | ||||
| ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa | ud.blurTransmissionTarget = this.blurTransmissionTarget && ud.transmissionRenderTarget.samples === 0 // todo: not working with msaa | ||||
| opaqueRender: false, | opaqueRender: false, | ||||
| transparentRender: false, | transparentRender: false, | ||||
| transmissionRender: true, | transmissionRender: true, | ||||
| }, renderFn) | |||||
| }, renderFn) // render to transparentTarget | |||||
| ud.blurTransmissionTarget = undefined | ud.blurTransmissionTarget = undefined | ||||
| ud.transmissionRenderTarget = undefined | ud.transmissionRenderTarget = undefined | ||||
| if (!renderer.info || renderer.info.render.calls > 0) { | if (!renderer.info || renderer.info.render.calls > 0) { | ||||
| // console.log('missive blit', renderer.info.render.frame) | // 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.uniforms.tDiffuse2.value = this.transparentTarget.texture | ||||
| this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | this._blendPass.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | ||||
| needsSwap = true | |||||
| needsSwap = true // writeBuffer has the data now. | |||||
| } | } | ||||
| // if needsSwap, writeBuffer has data, else readBuffer | |||||
| if (renderToScreen) { | if (renderToScreen) { | ||||
| this.renderToScreen = true | this.renderToScreen = true | ||||
| const tex = needsSwap ? writeBuffer?.texture : readBuffer?.texture | const tex = needsSwap ? writeBuffer?.texture : readBuffer?.texture | ||||
| } | } | ||||
| // 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) | if (!this.preserveTransparentTarget) | ||||
| this._releaseTransparentTarget() | this._releaseTransparentTarget() | ||||
| if (!this.preserveOpaqueTarget) | |||||
| this._releaseOpaqueTarget() | |||||
| this.needsSwap = needsSwap | this.needsSwap = needsSwap | ||||
| renderer.userData.mainRenderPass = undefined | renderer.userData.mainRenderPass = undefined | ||||
| } | } |
| import {IRenderTarget, RenderManager} from '../rendering' | import {IRenderTarget, RenderManager} from '../rendering' | ||||
| import { | |||||
| HalfFloatType, | |||||
| LinearFilter, | |||||
| LinearMipMapLinearFilter, | |||||
| NoColorSpace, | |||||
| RGBM16ColorSpace, | |||||
| UnsignedByteType, | |||||
| } from 'three' | |||||
| import {HalfFloatType, LinearFilter, NoColorSpace, RGBM16ColorSpace, UnsignedByteType} from 'three' | |||||
| import {IRenderManagerEvent, IRenderManagerOptions, IScene} from '../core' | import {IRenderManagerEvent, IRenderManagerOptions, IScene} from '../core' | ||||
| import {ExtendedRenderPass, ScreenPass, TViewerScreenShader} from '../postprocessing' | import {ExtendedRenderPass, ScreenPass, TViewerScreenShader} from '../postprocessing' | ||||
| import {uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | import {uiFolderContainer, UiObjectConfig} from 'uiconfig.js' | ||||
| readonly screenPass: ScreenPass | readonly screenPass: ScreenPass | ||||
| declare uiConfig: UiObjectConfig | declare uiConfig: UiObjectConfig | ||||
| static DEFAULT_MSAA_SAMPLES = 4 | |||||
| constructor({rgbm = true, msaa = false, depthBuffer = false, ...options}: ViewerRenderManagerOptions) { | constructor({rgbm = true, msaa = false, depthBuffer = false, ...options}: ViewerRenderManagerOptions) { | ||||
| super({ | super({ | ||||
| ...options, | ...options, | ||||
| targetOptions: { | targetOptions: { | ||||
| samples: msaa ? typeof msaa !== 'number' ? 4 : msaa : 0, | |||||
| samples: 0, | |||||
| // samples: msaa ? typeof msaa !== 'number' ? ViewerRenderManager.DEFAULT_MSAA_SAMPLES : msaa : 0, | |||||
| colorSpace: rgbm ? RGBM16ColorSpace : NoColorSpace, | colorSpace: rgbm ? RGBM16ColorSpace : NoColorSpace, | ||||
| type: rgbm ? UnsignedByteType : HalfFloatType, | type: rgbm ? UnsignedByteType : HalfFloatType, | ||||
| depthBuffer: depthBuffer, | depthBuffer: depthBuffer, | ||||
| generateMipmaps: msaa ? true : false, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||||
| minFilter: msaa ? LinearMipMapLinearFilter : LinearFilter, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||||
| generateMipmaps: /* msaa ? true : */false, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||||
| minFilter: /* msaa ? LinearMipMapLinearFilter : */LinearFilter, // todo: hack for now, fix blurTransmissionTarget in ExtendedRenderPass | |||||
| }, | }, | ||||
| }) | }) | ||||
| this.rgbm = rgbm | this.rgbm = rgbm |