| @@ -1,19 +1,27 @@ | |||
| import { | |||
| BufferGeometry, | |||
| Camera, | |||
| Color, | |||
| FrontSide, | |||
| HalfFloatType, | |||
| IUniform, | |||
| LinearSRGBColorSpace, | |||
| MeshNormalMaterial, | |||
| NearestFilter, | |||
| NoBlending, | |||
| Object3D, | |||
| Scene, | |||
| TangentSpaceNormalMap, | |||
| Texture, | |||
| TextureDataType, | |||
| WebGLRenderer, | |||
| WebGLRenderTarget, | |||
| } from 'three' | |||
| import {GBufferRenderPass} from '../../postprocessing' | |||
| import {ThreeViewer} from '../../viewer' | |||
| import {IShaderPropertiesUpdater} from '../../materials' | |||
| import {PipelinePassPlugin} from '../base/PipelinePassPlugin' | |||
| import type {IMaterial, PhysicalMaterial} from '../../core' | |||
| export type NormalBufferPluginEventTypes = '' | |||
| // type NormalBufferPluginTarget = WebGLMultipleRenderTargets | WebGLRenderTarget | |||
| @@ -28,7 +36,7 @@ export class NormalBufferPlugin | |||
| target?: NormalBufferPluginTarget | |||
| texture?: Texture | |||
| readonly material: MeshNormalMaterial = new MeshNormalMaterial({ | |||
| readonly material: MeshNormalMaterial = new MeshNormalMaterial2({ | |||
| blending: NoBlending, | |||
| }) | |||
| // private _gbufferPass?: IFilter<GBufferRenderPass<WebGLMultipleRenderTargets> | |||
| @@ -80,3 +88,44 @@ export class NormalBufferPlugin | |||
| } | |||
| 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 | |||
| } | |||
| } | |||
| @@ -10,16 +10,15 @@ export class ExtendedCopyPass extends ExtendedShaderPass { | |||
| vertexShader: CopyShader.vertexShader, | |||
| fragmentShader: glsl` | |||
| uniform float opacity; | |||
| uniform float alphaTest; | |||
| #include <alphatest_pars_fragment> | |||
| varying vec2 vUv; | |||
| 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 | |||
| gl_FragColor.a = 1.0; | |||
| diffuseColor.a = 1.0; | |||
| #endif | |||
| gl_FragColor = diffuseColor; | |||
| #include <encodings_fragment> | |||
| } | |||
| `, | |||
| @@ -1,7 +1,7 @@ | |||
| import {IPass} from './Pass' | |||
| import {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js' | |||
| 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 {serialize} from 'ts-browser-helpers' | |||
| import {IShaderPropertiesUpdater} from '../materials' | |||
| @@ -17,9 +17,9 @@ export class ExtendedShaderPass extends ShaderPass implements IPass { | |||
| @uiToggle('Enabled') @serialize() enabled = true | |||
| constructor(shader: Shader|ShaderMaterial2, ...textureID: string[]) { | |||
| constructor(shader: ShaderMaterial2|ShaderMaterialParameters, ...textureID: string[]) { | |||
| 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]) | |||
| this.setDirty = this.setDirty.bind(this) | |||
| } | |||
| @@ -3,13 +3,12 @@ import {Texture} from 'three' | |||
| import {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | |||
| import {ExtendedShaderPass} from './ExtendedShaderPass' | |||
| import {IPass} from './Pass' | |||
| import {glsl} from 'ts-browser-helpers' | |||
| export class GenericBlendTexturePass extends ExtendedShaderPass implements IPass { | |||
| constructor(uniforms: {[uniform: string]: IUniform}, blendFunc = 'c = a + b;', extraFrag = '', texture?: Texture) { | |||
| super({ | |||
| vertexShader: CopyShader.vertexShader, | |||
| fragmentShader: glsl` | |||
| fragmentShader: ` | |||
| varying vec2 vUv; | |||
| ${extraFrag} | |||
| void blend(in vec4 a, in vec4 b, inout vec4 c){ | |||
| @@ -1,12 +1,20 @@ | |||
| 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 {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js' | |||
| import {IPassID, IPipelinePass} from './Pass' | |||
| import {uiFolderContainer} from 'uiconfig.js' | |||
| 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') | |||
| export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'screen'> { | |||
| @@ -16,41 +24,63 @@ export class ScreenPass extends ExtendedShaderPass implements IPipelinePass<'scr | |||
| constructor(shader: TViewerScreenShader, ...textureID: string[]) { | |||
| super( | |||
| (<any>shader)?.fragmentShader || (<ShaderMaterial2>shader)?.isShaderMaterial ? <Shader|ShaderMaterial2>shader : | |||
| (<any>shader)?.fragmentShader || (<ShaderMaterial2>shader)?.isShaderMaterial ? <ShaderMaterialParameters|ShaderMaterial2>shader : | |||
| makeScreenShader(shader), | |||
| ...textureID.length ? textureID : ['tDiffuse']) | |||
| } | |||
| outputColorSpace: ColorSpace = SRGBColorSpace | |||
| private _lastReadBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | |||
| render(renderer: IWebGLRenderer, writeBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget | null, readBuffer?: WebGLMultipleRenderTargets | WebGLRenderTarget, deltaTime?: number, maskActive?: boolean) { | |||
| const colorSpace = renderer.outputColorSpace | |||
| if (!writeBuffer || this.renderToScreen) renderer.outputColorSpace = this.outputColorSpace | |||
| else console.warn('ScreenPass: outputColorSpace is ignored when renderToScreen is false') | |||
| super.render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) | |||
| this._lastReadBuffer = readBuffer | |||
| 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 { | |||
| ...CopyShader, | |||
| fragmentShader: ` | |||
| varying vec2 vUv; | |||
| #include <alphatest_pars_fragment> | |||
| ${Array.isArray(shader) ? shader[0] : (<any>shader)?.pars || ''} | |||
| 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> | |||
| }`, | |||
| uniforms: { | |||
| tDiffuse: {value: null}, | |||
| }, | |||
| } | |||
| transparent: true, | |||
| blending: NoBlending, | |||
| side: FrontSide, | |||
| } as ShaderMaterialParameters | |||
| } | |||
| @@ -476,8 +476,8 @@ export class RenderManager extends RenderTargetManager<IRenderManagerEvent, IRen | |||
| {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 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.setClearAlpha(a ?? alpha) | |||
| const lastTarget = this._renderer.getRenderTarget() | |||
| const activeCubeFace = this._renderer.getActiveCubeFace() | |||
| const activeMipLevel = this._renderer.getActiveMipmapLevel() | |||
| @@ -44,7 +44,7 @@ export class ViewerRenderManager extends RenderManager { | |||
| this._renderer.userData.renderTransmissionPass = !doTransmissionFix // hack. used in WebGLRenderer.js | |||
| 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.screenPass) | |||
| } | |||