threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
157 lines (133 loc) • 5.54 kB
text/typescript
// noinspection ES6PreferShortImport
import {uiDropdown, uiFolderContainer, uiSlider, uiToggle} from 'uiconfig.js'
import {
ACESFilmicToneMapping,
AgXToneMapping,
CineonToneMapping,
CustomToneMapping,
LinearToneMapping,
Object3D,
ReinhardToneMapping,
ShaderChunk,
ToneMapping,
Vector4,
WebGLRenderer,
} from 'three'
import {glsl, onChange, serialize} from 'ts-browser-helpers'
import {IMaterial} from '../../core'
import {updateBit} from '../../utils'
import {uniform} from '../../three'
import Uncharted2ToneMappingShader from './shaders/Uncharted2ToneMapping.glsl'
import TonemapShader from './shaders/TonemapPlugin.pars.glsl'
import TonemapShaderPatch from './shaders/TonemapPlugin.patch.glsl'
import {AScreenPassExtensionPlugin} from './AScreenPassExtensionPlugin'
import {GBufferUpdaterContext} from '../pipeline/GBufferMaterial'
// eslint-disable-next-line @typescript-eslint/naming-convention
export const Uncharted2Tonemapping: ToneMapping = CustomToneMapping
/**
* Tonemap Plugin
*
* Adds an extension to {@link ScreenPass} material
* for applying tonemapping on the final buffer before rendering to screen.
*
* Also adds support for Uncharted2 tone-mapping.
* @category Plugins
*/
export class TonemapPlugin extends AScreenPassExtensionPlugin {
static readonly PluginType = 'Tonemap'
readonly extraUniforms = {
toneMappingContrast: {value: 1},
toneMappingSaturation: {value: 1},
} as const
readonly extraDefines = {
['TONEMAP_BACKGROUND']: ()=>this.tonemapBackground === false || this._viewer?.scene.backgroundTonemap === false ? '0' : '1',
} as const
enabled = true
toneMapping: ToneMapping = ACESFilmicToneMapping
/**
* Global toggle to apply tonemapping on the background.
* The tonemapping is not applied if either this or {@link RootScene.backgroundTonemap} is false.
*/
tonemapBackground = true
// todo handle legacy deserialize
// moved to ScreenPass.clipBackground
// @onChange(TonemapPlugin.prototype.setDirty)
// @uiToggle('Clip Background')
// @serialize() clipBackground = false
exposure = 1
saturation: number
contrast: number
/**
* The priority of the material extension when applied to the material in ScreenPass
* set to very low priority, so applied at the end
*/
priority = -100
parsFragmentSnippet = () => {
if (this.isDisabled()) return ''
return glsl`
uniform float toneMappingContrast;
uniform float toneMappingSaturation;
${TonemapShader}
`
}
protected _shaderPatch = TonemapShaderPatch
private _rendererState: any = {}
onObjectRender(_: Object3D, material: IMaterial, renderer: WebGLRenderer): void {
if (this.isDisabled()) return
const {toneMapping, toneMappingExposure} = renderer
this._rendererState.toneMapping = toneMapping
this._rendererState.toneMappingExposure = toneMappingExposure
renderer.toneMapping = this.toneMapping
renderer.toneMappingExposure = this.exposure
material.toneMapped = true
material.needsUpdate = true
}
onAfterRender(_: Object3D, _1: IMaterial, renderer: WebGLRenderer): void {
renderer.toneMapping = this._rendererState.toneMapping
renderer.toneMappingExposure = this._rendererState.toneMappingExposure
}
fromJSON(data: any, meta?: any): this|null|Promise<this|null> {
// legacy
if (data.extension) {
if (data.clipBackground !== undefined) {
if (this._viewer) this._viewer.renderManager.screenPass.clipBackground = data.clipBackground
else console.warn('TonemapPlugin: no viewer attached, clipBackground ignored')
delete data.clipBackground
}
}
return super.fromJSON(data, meta)
}
// TODO: add gBufferData or just tonemapEnabled to the scene material UI with an extension like bloom
updateGBufferFlags(data: Vector4, c: GBufferUpdaterContext): void {
const x = (c.material.userData.gBufferData?.tonemapEnabled ?? c.material?.userData.postTonemap) === false ? 0 : 1
data.w = updateBit(data.w, 1, x) // 2nd Bit
super.updateGBufferFlags(data, c)
}
static {
// Add support for Uncharted2 tone mapping
ShaderChunk.tonemapping_pars_fragment = ShaderChunk.tonemapping_pars_fragment.replace('vec3 CustomToneMapping( vec3 color ) { return color; }', Uncharted2ToneMappingShader)
}
}