| import {AViewerPluginSync, ISerializedConfig, ThreeViewer} from '../../viewer' | import {AViewerPluginSync, ISerializedConfig, ThreeViewer} from '../../viewer' | ||||
| import {AnyFunction, serialize} from 'ts-browser-helpers' | import {AnyFunction, serialize} from 'ts-browser-helpers' | ||||
| import {SerializationMetaType} from '../../utils' | import {SerializationMetaType} from '../../utils' | ||||
| import {uiConfig, uiToggle} from 'uiconfig.js' | |||||
| export abstract class PipelinePassPlugin<T extends IPipelinePass, TPassId extends IPassID, TEvent extends string, TViewer extends ThreeViewer=ThreeViewer> extends AViewerPluginSync<TEvent, TViewer> { | export abstract class PipelinePassPlugin<T extends IPipelinePass, TPassId extends IPassID, TEvent extends string, TViewer extends ThreeViewer=ThreeViewer> extends AViewerPluginSync<TEvent, TViewer> { | ||||
| abstract passId: TPassId | abstract passId: TPassId | ||||
| @serialize() | |||||
| @uiToggle('Enabled') | |||||
| get enabled(): boolean { | |||||
| return this._pass?.enabled || this._enabledTemp | |||||
| } | |||||
| set enabled(value: boolean) { | |||||
| if (this._pass) this._pass.enabled = value | |||||
| this._enabledTemp = value | |||||
| } | |||||
| @uiConfig() | |||||
| @serialize('pass') | @serialize('pass') | ||||
| protected _pass?: T | protected _pass?: T | ||||
| abstract createPass(v:TViewer):T | abstract createPass(v:TViewer):T | ||||
| protected _beforeRender(): boolean {return this._pass?.enabled && this.enabled || false} | protected _beforeRender(): boolean {return this._pass?.enabled && this.enabled || false} | ||||
| private _enabledTemp = true // to save enabled state when pass is not yet created | private _enabledTemp = true // to save enabled state when pass is not yet created | ||||
| @serialize() | |||||
| get enabled(): boolean { | |||||
| return this._pass?.enabled || this._enabledTemp | |||||
| } | |||||
| set enabled(value: boolean) { | |||||
| if (this._pass) this._pass.enabled = value | |||||
| this._enabledTemp = value | |||||
| } | |||||
| constructor() { | constructor() { | ||||
| super() | super() |
| import {ThreeViewer} from '../../viewer' | import {ThreeViewer} from '../../viewer' | ||||
| import {IShaderPropertiesUpdater} from '../../materials' | import {IShaderPropertiesUpdater} from '../../materials' | ||||
| import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | ||||
| import {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> | ||||
| @uiFolderContainer('Depth Buffer Plugin') | |||||
| export class DepthBufferPlugin | export class DepthBufferPlugin | ||||
| extends PipelinePassPlugin<DepthBufferPluginPass, 'depth', DepthBufferPluginEventTypes> | extends PipelinePassPlugin<DepthBufferPluginPass, 'depth', DepthBufferPluginEventTypes> | ||||
| implements IShaderPropertiesUpdater { | implements IShaderPropertiesUpdater { | ||||
| public static readonly PluginType = 'DepthBufferPlugin' | public static readonly PluginType = 'DepthBufferPlugin' | ||||
| target?: DepthBufferPluginTarget | target?: DepthBufferPluginTarget | ||||
| texture?: Texture | |||||
| @uiImage('Depth Buffer' /* {readOnly: true}*/) texture?: Texture | |||||
| readonly material: MeshDepthMaterial = new MeshDepthMaterial({ | readonly material: MeshDepthMaterial = new MeshDepthMaterial({ | ||||
| depthPacking: BasicDepthPacking, | depthPacking: BasicDepthPacking, | ||||
| blending: NoBlending, | blending: NoBlending, | ||||
| depthBuffer: true, | depthBuffer: true, | ||||
| samples: v.renderManager.composerTarget.samples || 0, | samples: v.renderManager.composerTarget.samples || 0, | ||||
| type: this.bufferType, | type: this.bufferType, | ||||
| // magFilter: NearestFilter, | |||||
| // minFilter: NearestFilter, | |||||
| // generateMipmaps: false, | |||||
| // encoding: LinearEncoding, | |||||
| // magFilter: NearestFilter, | |||||
| // minFilter: NearestFilter, | |||||
| // generateMipmaps: false, | |||||
| // encoding: LinearEncoding, | |||||
| }) | }) | ||||
| this.texture = this.target.texture | this.texture = this.target.texture | ||||
| this.texture.name = 'depthBuffer' | this.texture.name = 'depthBuffer' | ||||
| constructor( | constructor( | ||||
| public readonly bufferType: TextureDataType = UnsignedByteType, | public readonly bufferType: TextureDataType = UnsignedByteType, | ||||
| public readonly isPrimaryGBuffer = false | |||||
| public readonly isPrimaryGBuffer = false, | |||||
| enabled = true, | |||||
| ) { | ) { | ||||
| super() | super() | ||||
| this.enabled = enabled | |||||
| } | } | ||||
| onRemove(viewer: ThreeViewer): void { | onRemove(viewer: ThreeViewer): void { |
| import {IShaderPropertiesUpdater} from '../../materials' | import {IShaderPropertiesUpdater} from '../../materials' | ||||
| import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | ||||
| import type {IMaterial, PhysicalMaterial} from '../../core' | import type {IMaterial, PhysicalMaterial} from '../../core' | ||||
| import {uiFolderContainer, uiImage} from 'uiconfig.js' | |||||
| 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> | ||||
| @uiFolderContainer('Normal Buffer Plugin') | |||||
| export class NormalBufferPlugin | export class NormalBufferPlugin | ||||
| extends PipelinePassPlugin<NormalBufferPluginPass, 'normal', NormalBufferPluginEventTypes> | extends PipelinePassPlugin<NormalBufferPluginPass, 'normal', NormalBufferPluginEventTypes> | ||||
| implements IShaderPropertiesUpdater { | implements IShaderPropertiesUpdater { | ||||
| public static readonly PluginType = 'NormalBufferPlugin' | public static readonly PluginType = 'NormalBufferPlugin' | ||||
| target?: NormalBufferPluginTarget | target?: NormalBufferPluginTarget | ||||
| texture?: Texture | |||||
| @uiImage('Normal Buffer' /* {readOnly: true}*/) texture?: Texture | |||||
| readonly material: MeshNormalMaterial = new MeshNormalMaterial2({ | readonly material: MeshNormalMaterial = new MeshNormalMaterial2({ | ||||
| blending: NoBlending, | blending: NoBlending, | ||||
| }) | }) | ||||
| constructor( | constructor( | ||||
| public readonly bufferType: TextureDataType = HalfFloatType, | public readonly bufferType: TextureDataType = HalfFloatType, | ||||
| enabled = true, | |||||
| ) { | ) { | ||||
| super() | super() | ||||
| this.enabled = enabled | |||||
| } | } | ||||
| onRemove(viewer: ThreeViewer): void { | onRemove(viewer: ThreeViewer): void { |
| import {SRGBColorSpace, Vector4, WebGLRenderTarget} from 'three' | import {SRGBColorSpace, Vector4, WebGLRenderTarget} from 'three' | ||||
| import styles from './RenderTargetPreviewPlugin.css' | import styles from './RenderTargetPreviewPlugin.css' | ||||
| import {CustomContextMenu} from '../../utils' | import {CustomContextMenu} from '../../utils' | ||||
| import {uiFolderContainer, uiToggle} from 'uiconfig.js' | |||||
| @uiFolderContainer('Render Target Preview Plugin') | |||||
| export class RenderTargetPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> { | export class RenderTargetPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> { | ||||
| static readonly PluginType = 'RenderTargetPreviewPlugin' | static readonly PluginType = 'RenderTargetPreviewPlugin' | ||||
| @uiToggle('Enabled') | |||||
| @onChange(RenderTargetPreviewPlugin.prototype.refreshUi) enabled = true | @onChange(RenderTargetPreviewPlugin.prototype.refreshUi) enabled = true | ||||
| toJSON: any = null | toJSON: any = null | ||||
| mainDiv: HTMLDivElement = createDiv({id: 'RenderTargetPreviewPluginContainer'}) | |||||
| mainDiv: HTMLDivElement = createDiv({id: 'RenderTargetPreviewPluginContainer', addToBody: false}) | |||||
| stylesheet?: HTMLStyleElement | stylesheet?: HTMLStyleElement | ||||
| constructor() { | |||||
| constructor(enabled = true) { | |||||
| super() | super() | ||||
| this.enabled = enabled | |||||
| } | } | ||||
| targetBlocks: { | targetBlocks: { | ||||
| } | } | ||||
| addTarget(target: ValOrFunc<IRenderTarget|undefined>, name: string, transparent = false, originalColorSpace = false, visible = true): this { | addTarget(target: ValOrFunc<IRenderTarget|undefined>, name: string, transparent = false, originalColorSpace = false, visible = true): this { | ||||
| if (!target) return this | |||||
| const div = document.createElement('div') | const div = document.createElement('div') | ||||
| const targetDef = {target, name, transparent, div, originalColorSpace, visible} | const targetDef = {target, name, transparent, div, originalColorSpace, visible} | ||||
| div.classList.add('RenderTargetPreviewPluginTarget') | div.classList.add('RenderTargetPreviewPluginTarget') | ||||
| if (!targetDef.visible) div.classList.add('RenderTargetPreviewPluginCollapsed') | |||||
| const header = document.createElement('div') | const header = document.createElement('div') | ||||
| header.classList.add('RenderTargetPreviewPluginTargetHeader') | header.classList.add('RenderTargetPreviewPluginTargetHeader') | ||||
| header.innerText = name | header.innerText = name |
| private _plugins: IViewerPlugin[] = [] | private _plugins: IViewerPlugin[] = [] | ||||
| setupPlugins<T extends IViewerPlugin>(...plugins: Class<T>[]): void { | |||||
| setupPlugins(...plugins: Class<IViewerPlugin>[]): void { | |||||
| plugins.forEach(plugin => this.setupPluginUi(plugin)) | plugins.forEach(plugin => this.setupPluginUi(plugin)) | ||||
| } | } | ||||
| import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js' | import {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js' | ||||
| import {IPassID, IPipelinePass} from './Pass' | import {IPassID, IPipelinePass} from './Pass' | ||||
| import {ICamera, IMaterial, IRenderManager, IScene, IWebGLRenderer, PhysicalMaterial} from '../core' | import {ICamera, IMaterial, IRenderManager, IScene, IWebGLRenderer, PhysicalMaterial} from '../core' | ||||
| import {uiFolderContainer, UiObjectConfig, uiToggle} from 'uiconfig.js' | |||||
| export class GBufferRenderPass<TP extends IPassID, T extends WebGLMultipleRenderTargets | WebGLRenderTarget> extends RenderPass implements IPipelinePass<TP> { // todo: extend from jittered? | |||||
| @uiFolderContainer<GBufferRenderPass>((c)=>c.passId + ' Render Pass') | |||||
| export class GBufferRenderPass<TP extends IPassID=IPassID, T extends WebGLMultipleRenderTargets | WebGLRenderTarget=WebGLMultipleRenderTargets | WebGLRenderTarget> extends RenderPass implements IPipelinePass<TP> { // todo: extend from jittered? | |||||
| readonly isGBufferRenderPass = true | readonly isGBufferRenderPass = true | ||||
| uiConfig: UiObjectConfig | |||||
| @uiToggle('Enabled') enabled = true | |||||
| scene?: IScene | scene?: IScene | ||||
| before?: IPassID[] | before?: IPassID[] |
| upgradeWebGLRenderer, | upgradeWebGLRenderer, | ||||
| } from '../core' | } from '../core' | ||||
| import {base64ToArrayBuffer, canvasFlipY, Class, onChange2, serializable, serialize, ValOrArr} from 'ts-browser-helpers' | import {base64ToArrayBuffer, canvasFlipY, Class, onChange2, serializable, serialize, ValOrArr} from 'ts-browser-helpers' | ||||
| import {uiConfig, uiFolderContainer, uiMonitor, uiSlider, uiToggle} from 'uiconfig.js' | |||||
| import {uiButton, uiConfig, uiFolderContainer, uiMonitor, uiSlider, uiToggle} from 'uiconfig.js' | |||||
| import {generateUUID, textureDataToImageData} from '../three' | import {generateUUID, textureDataToImageData} from '../three' | ||||
| import {BlobExt, EXRExporter2} from '../assetmanager' | import {BlobExt, EXRExporter2} from '../assetmanager' | ||||
| @onChange2(RenderManager.prototype.rebuildPipeline) | @onChange2(RenderManager.prototype.rebuildPipeline) | ||||
| public autoBuildPipeline = true | public autoBuildPipeline = true | ||||
| @uiButton('Rebuild Pipeline') | |||||
| rebuildPipeline(setDirty = true): void { | rebuildPipeline(setDirty = true): void { | ||||
| this._passesNeedsUpdate = true | this._passesNeedsUpdate = true | ||||
| if (setDirty) this._updated({change: 'rebuild'}) | if (setDirty) this._updated({change: 'rebuild'}) |