| import { | import { | ||||
| BufferGeometry, | |||||
| Camera, | |||||
| Color, | Color, | ||||
| FrontSide, | |||||
| HalfFloatType, | HalfFloatType, | ||||
| IUniform, | IUniform, | ||||
| LinearSRGBColorSpace, | LinearSRGBColorSpace, | ||||
| MeshNormalMaterial, | MeshNormalMaterial, | ||||
| NearestFilter, | NearestFilter, | ||||
| NoBlending, | NoBlending, | ||||
| Object3D, | |||||
| Scene, | |||||
| TangentSpaceNormalMap, | |||||
| Texture, | Texture, | ||||
| TextureDataType, | TextureDataType, | ||||
| WebGLRenderer, | |||||
| WebGLRenderTarget, | WebGLRenderTarget, | ||||
| } from 'three' | } from 'three' | ||||
| import {GBufferRenderPass} from '../../postprocessing' | import {GBufferRenderPass} from '../../postprocessing' | ||||
| 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 type {IMaterial, PhysicalMaterial} from '../../core' | |||||
| export type NormalBufferPluginEventTypes = '' | export type NormalBufferPluginEventTypes = '' | ||||
| // type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | // type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | ||||
| target?: NormalBufferPluginTarget | target?: NormalBufferPluginTarget | ||||
| texture?: Texture | texture?: Texture | ||||
| readonly material: MeshNormalMaterial = new MeshNormalMaterial({ | |||||
| readonly material: MeshNormalMaterial = new MeshNormalMaterial2({ | |||||
| blending: NoBlending, | blending: NoBlending, | ||||
| }) | }) | ||||
| // private _gbufferPass?: IFilter<GBufferRenderPass<WebGLMultipleRenderTargets> | // private _gbufferPass?: IFilter<GBufferRenderPass<WebGLMultipleRenderTargets> | ||||
| } | } | ||||
| class MeshNormalMaterial2 extends MeshNormalMaterial { | |||||
| onBeforeRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D) { | |||||
| super.onBeforeRender(renderer, scene, camera, geometry, object) | |||||
| if (!(object as any).material) return | |||||
| const material = (object as any).material as IMaterial & Partial<PhysicalMaterial> | |||||
| if (material.bumpMap !== undefined) this.bumpMap = material.bumpMap | |||||
| if (material.bumpScale !== undefined) this.bumpScale = material.bumpScale | |||||
| if (material.normalMap !== undefined) this.normalMap = material.normalMap | |||||
| if (material.normalMapType !== undefined) this.normalMapType = material.normalMapType | |||||
| if (material.normalScale !== undefined) this.normalScale.copy(material.normalScale) | |||||
| if (material.displacementMap !== undefined) this.displacementMap = material.displacementMap | |||||
| if (material.displacementScale !== undefined) this.displacementScale = material.displacementScale | |||||
| if (material.displacementBias !== undefined) this.displacementBias = material.displacementBias | |||||
| if (material.flatShading !== undefined) this.flatShading = material.flatShading | |||||
| if (material.side !== undefined) this.side = material.side | |||||
| } | |||||
| onAfterRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D) { | |||||
| super.onAfterRender(renderer, scene, camera, geometry, object) | |||||
| this.bumpMap = null | |||||
| this.bumpScale = 1 | |||||
| this.normalMap = null | |||||
| this.normalMapType = TangentSpaceNormalMap | |||||
| this.displacementMap = null | |||||
| this.displacementScale = 1 | |||||
| this.displacementBias = 0 | |||||
| this.flatShading = false | |||||
| this.side = FrontSide | |||||
| } | |||||
| } |
| vertexShader: CopyShader.vertexShader, | vertexShader: CopyShader.vertexShader, | ||||
| fragmentShader: glsl` | fragmentShader: glsl` | ||||
| uniform float opacity; | uniform float opacity; | ||||
| uniform float alphaTest; | |||||
| #include <alphatest_pars_fragment> | |||||
| varying vec2 vUv; | varying vec2 vUv; | ||||
| void main() { | void main() { | ||||
| gl_FragColor = tDiffuseTexelToLinear(texture2D(tDiffuse, vUv)) * opacity; | |||||
| #ifdef USE_ALPHATEST | |||||
| if ( gl_FragColor.a < alphaTest ) discard; | |||||
| #endif | |||||
| vec4 diffuseColor = tDiffuseTexelToLinear(texture2D(tDiffuse, vUv)) * opacity; | |||||
| #include <alphatest_fragment> | |||||
| #ifdef OPAQUE | #ifdef OPAQUE | ||||
| gl_FragColor.a = 1.0; | |||||
| diffuseColor.a = 1.0; | |||||
| #endif | #endif | ||||
| gl_FragColor = diffuseColor; | |||||
| #include <encodings_fragment> | #include <encodings_fragment> | ||||
| } | } | ||||
| `, | `, |
| import {IPass} from './Pass' | import {IPass} from './Pass' | ||||
| import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js' | import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js' | ||||
| import {ExtendedShaderMaterial, IWebGLRenderer, ShaderMaterial2} from '../core' | import {ExtendedShaderMaterial, IWebGLRenderer, ShaderMaterial2} from '../core' | ||||
| import {Shader, WebGLMultipleRenderTargets, WebGLRenderTarget} from 'three' | |||||
| import {Shader, ShaderMaterialParameters, WebGLMultipleRenderTargets, WebGLRenderTarget} from 'three' | |||||
| import {uiToggle} from 'uiconfig.js' | import {uiToggle} from 'uiconfig.js' | ||||
| import {serialize} from 'ts-browser-helpers' | import {serialize} from 'ts-browser-helpers' | ||||
| import {IShaderPropertiesUpdater} from '../materials' | import {IShaderPropertiesUpdater} from '../materials' | ||||
| @uiToggle('Enabled') @serialize() enabled = true | @uiToggle('Enabled') @serialize() enabled = true | ||||
| constructor(shader: Shader|ShaderMaterial2, ...textureID: string[]) { | |||||
| constructor(shader: ShaderMaterial2|ShaderMaterialParameters, ...textureID: string[]) { | |||||
| super( | super( | ||||
| (<ShaderMaterial2>shader).isMaterial ? <ShaderMaterial2>shader : new ExtendedShaderMaterial(<Shader>shader, textureID), | |||||
| (<ShaderMaterial2>shader).isMaterial ? <ShaderMaterial2>shader : new ExtendedShaderMaterial(<ShaderMaterialParameters>shader, textureID), | |||||
| textureID.length < 1 ? ExtendedShaderPass.DEFAULT_TEX_ID : textureID[0]) | textureID.length < 1 ? ExtendedShaderPass.DEFAULT_TEX_ID : textureID[0]) | ||||
| this.setDirty = this.setDirty.bind(this) | this.setDirty = this.setDirty.bind(this) | ||||
| } | } |
| import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | ||||
| import {ExtendedShaderPass} from './ExtendedShaderPass' | import {ExtendedShaderPass} from './ExtendedShaderPass' | ||||
| import {IPass} from './Pass' | import {IPass} from './Pass' | ||||
| import {glsl} from 'ts-browser-helpers' | |||||
| export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass { | export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass { | ||||
| constructor(uniforms: {[uniform: string]: IUniform}, blendFunc = 'c = a + b;', extraFrag = '', texture?: Texture) { | constructor(uniforms: {[uniform: string]: IUniform}, blendFunc = 'c = a + b;', extraFrag = '', texture?: Texture) { | ||||
| super({ | super({ | ||||
| vertexShader: CopyShader.vertexShader, | vertexShader: CopyShader.vertexShader, | ||||
| fragmentShader: glsl` | |||||
| fragmentShader: ` | |||||
| varying vec2 vUv; | varying vec2 vUv; | ||||
| ${extraFrag} | ${extraFrag} | ||||
| void blend(in vec4 a, in vec4 b, inout vec4 c){ | void blend(in vec4 a, in vec4 b, inout vec4 c){ |
| import {ExtendedShaderPass} from './ExtendedShaderPass' | import {ExtendedShaderPass} from './ExtendedShaderPass' | ||||
| import {ColorSpace, Shader, SRGBColorSpace, WebGLMultipleRenderTargets, WebGLRenderTarget} from 'three' | |||||
| import { | |||||
| ColorSpace, | |||||
| FrontSide, | |||||
| NoBlending, | |||||
| ShaderMaterialParameters, | |||||
| SRGBColorSpace, | |||||
| WebGLMultipleRenderTargets, | |||||
| WebGLRenderTarget, | |||||
| } from 'three' | |||||
| import {IWebGLRenderer, ShaderMaterial2} from '../core' | import {IWebGLRenderer, ShaderMaterial2} from '../core' | ||||
| import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | ||||
| import {IPassID, IPipelinePass} from './Pass' | import {IPassID, IPipelinePass} from './Pass' | ||||
| import {uiFolderContainer} from 'uiconfig.js' | import {uiFolderContainer} from 'uiconfig.js' | ||||
| export type TViewerScreenShaderFrag = string | [string, string] | {pars?: string, main: string} | export type TViewerScreenShaderFrag = string | [string, string] | {pars?: string, main: string} | ||||
| export type TViewerScreenShader = TViewerScreenShaderFrag | Shader | ShaderMaterial2 | |||||
| export type TViewerScreenShader = TViewerScreenShaderFrag | ShaderMaterialParameters | ShaderMaterial2 | |||||
| @uiFolderContainer('Screen Pass') | @uiFolderContainer('Screen Pass') | ||||
| export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> { | export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> { | ||||
| constructor(shader: TViewerScreenShader, ...textureID: string[]) { | constructor(shader: TViewerScreenShader, ...textureID: string[]) { | ||||
| super( | super( | ||||
| (<any>shader)?.fragmentShader || (<ShaderMaterial2>shader)?.isShaderMaterial ? <Shader|ShaderMaterial2>shader : | |||||
| (<any>shader)?.fragmentShader || (<ShaderMaterial2>shader)?.isShaderMaterial ? <ShaderMaterialParameters|ShaderMaterial2>shader : | |||||
| makeScreenShader(shader), | makeScreenShader(shader), | ||||
| ...textureID.length ? textureID : ['tDiffuse']) | ...textureID.length ? textureID : ['tDiffuse']) | ||||
| } | } | ||||
| outputColorSpace: ColorSpace = SRGBColorSpace | outputColorSpace: ColorSpace = SRGBColorSpace | ||||
| private _lastReadBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | |||||
| 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) { | ||||
| const colorSpace = renderer.outputColorSpace | const colorSpace = renderer.outputColorSpace | ||||
| if (!writeBuffer || this.renderToScreen) renderer.outputColorSpace = this.outputColorSpace | if (!writeBuffer || this.renderToScreen) renderer.outputColorSpace = this.outputColorSpace | ||||
| else console.warn('ScreenPass: outputColorSpace is ignored when renderToScreen is false') | else console.warn('ScreenPass: outputColorSpace is ignored when renderToScreen is false') | ||||
| super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | ||||
| this._lastReadBuffer = readBuffer | |||||
| renderer.outputColorSpace = colorSpace | renderer.outputColorSpace = colorSpace | ||||
| } | } | ||||
| reRender(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | null, deltaTime?: number, maskActive?: boolean) { | |||||
| if (this._lastReadBuffer) this.render(renderer, writeBuffer, this._lastReadBuffer, deltaTime, maskActive) | |||||
| } | |||||
| dispose() { | |||||
| this._lastReadBuffer = undefined | |||||
| super.dispose() | |||||
| } | |||||
| } | } | ||||
| function makeScreenShader(shader: string | [string, string] | {pars?: string; main: string} | Shader | ShaderMaterial2) { | |||||
| function makeScreenShader(shader: string | [string, string] | {pars?: string; main: string} | ShaderMaterialParameters | ShaderMaterial2) { | |||||
| return { | return { | ||||
| ...CopyShader, | ...CopyShader, | ||||
| fragmentShader: ` | fragmentShader: ` | ||||
| varying vec2 vUv; | varying vec2 vUv; | ||||
| #include <alphatest_pars_fragment> | |||||
| ${Array.isArray(shader) ? shader[0] : (<any>shader)?.pars || ''} | ${Array.isArray(shader) ? shader[0] : (<any>shader)?.pars || ''} | ||||
| void main() { | void main() { | ||||
| gl_FragColor = tDiffuseTexelToLinear (texture2D(tDiffuse, vUv)); | |||||
| vec4 diffuseColor = tDiffuseTexelToLinear (texture2D(tDiffuse, vUv)); | |||||
| ${Array.isArray(shader) ? shader[1] : typeof shader === 'string' ? shader : (shader as any)?.main || ''} | |||||
| #glMarker | |||||
| ${Array.isArray(shader) ? shader[1] : typeof shader === 'string' ? shader : (shader as any)?.main || ''} | |||||
| #include <alphatest_fragment> | |||||
| #ifdef OPAQUE | |||||
| diffuseColor.a = 1.0; | |||||
| #endif | |||||
| gl_FragColor = diffuseColor; | |||||
| #include <encodings_fragment> | #include <encodings_fragment> | ||||
| }`, | }`, | ||||
| uniforms: { | uniforms: { | ||||
| tDiffuse: {value: null}, | tDiffuse: {value: null}, | ||||
| }, | }, | ||||
| } | |||||
| transparent: true, | |||||
| blending: NoBlending, | |||||
| side: FrontSide, | |||||
| } as ShaderMaterialParameters | |||||
| } | } | ||||
| {r?: number, g?: number, b?: number, a?: number, target?: IRenderTarget, depth?: boolean, stencil?: boolean, viewport?: Vector4}): void { | {r?: number, g?: number, b?: number, a?: number, target?: IRenderTarget, depth?: boolean, stencil?: boolean, viewport?: Vector4}): void { | ||||
| const color = this._renderer.getClearColor(new Color()) | const color = this._renderer.getClearColor(new Color()) | ||||
| const alpha = this._renderer.getClearAlpha() | const alpha = this._renderer.getClearAlpha() | ||||
| this._renderer.setClearAlpha(a ?? alpha) | |||||
| this._renderer.setClearColor(new Color(r ?? color.r, g ?? color.g, b ?? color.b)) | this._renderer.setClearColor(new Color(r ?? color.r, g ?? color.g, b ?? color.b)) | ||||
| this._renderer.setClearAlpha(a ?? alpha) | |||||
| const lastTarget = this._renderer.getRenderTarget() | const lastTarget = this._renderer.getRenderTarget() | ||||
| const activeCubeFace = this._renderer.getActiveCubeFace() | const activeCubeFace = this._renderer.getActiveCubeFace() | ||||
| const activeMipLevel = this._renderer.getActiveMipmapLevel() | const activeMipLevel = this._renderer.getActiveMipmapLevel() |
| this._renderer.userData.renderTransmissionPass = !doTransmissionFix // hack. used in WebGLRenderer.js | this._renderer.userData.renderTransmissionPass = !doTransmissionFix // hack. used in WebGLRenderer.js | ||||
| this.renderPass = new ExtendedRenderPass(this) | this.renderPass = new ExtendedRenderPass(this) | ||||
| this.screenPass = new ScreenPass(options.screenShader || '') // todo gamma correction by default? | |||||
| this.screenPass = new ScreenPass(options.screenShader || '') | |||||
| this.registerPass(this.renderPass) | this.registerPass(this.renderPass) | ||||
| this.registerPass(this.screenPass) | this.registerPass(this.screenPass) | ||||
| } | } |