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.
148 lines • 6.31 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
// noinspection ES6PreferShortImport
import { uiDropdown, uiFolderContainer, uiSlider, uiToggle } from 'uiconfig.js';
import { ACESFilmicToneMapping, AgXToneMapping, CineonToneMapping, CustomToneMapping, LinearToneMapping, ReinhardToneMapping, ShaderChunk, } from 'three';
import { glsl, onChange, serialize } from 'ts-browser-helpers';
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 { matDefineBool } from '../../three/utils/decorators';
// eslint-disable-next-line @typescript-eslint/naming-convention
export const Uncharted2Tonemapping = 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
*/
let TonemapPlugin = class TonemapPlugin extends AScreenPassExtensionPlugin {
constructor() {
super(...arguments);
this.extraUniforms = {
toneMappingContrast: { value: 1 },
toneMappingSaturation: { value: 1 },
};
this.extraDefines = {
['TONEMAP_BACKGROUND']: '1',
};
this.enabled = true;
this.toneMapping = ACESFilmicToneMapping;
this.tonemapBackground = true;
// todo handle legacy deserialize
// @onChange(TonemapPlugin.prototype.setDirty)
// @uiToggle('Clip Background')
// @serialize() clipBackground = false
this.exposure = 1;
/**
* The priority of the material extension when applied to the material in ScreenPass
* set to very low priority, so applied at the end
*/
this.priority = -100;
this.parsFragmentSnippet = () => {
if (this.isDisabled())
return '';
return glsl `
uniform float toneMappingContrast;
uniform float toneMappingSaturation;
${TonemapShader}
`;
};
this._shaderPatch = TonemapShaderPatch;
this._rendererState = {};
}
onObjectRender(_, material, renderer) {
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(_, _1, renderer) {
renderer.toneMapping = this._rendererState.toneMapping;
renderer.toneMappingExposure = this._rendererState.toneMappingExposure;
}
fromJSON(data, meta) {
// 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, c) {
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);
}
};
TonemapPlugin.PluginType = 'Tonemap';
(() => {
// Add support for Uncharted2 tone mapping
ShaderChunk.tonemapping_pars_fragment = ShaderChunk.tonemapping_pars_fragment.replace('vec3 CustomToneMapping( vec3 color ) { return color; }', Uncharted2ToneMappingShader);
})();
__decorate([
serialize(),
onChange(TonemapPlugin.prototype.setDirty),
uiToggle('Enabled')
], TonemapPlugin.prototype, "enabled", void 0);
__decorate([
uiDropdown('Mode', [
['Linear', LinearToneMapping],
['Reinhard', ReinhardToneMapping],
['Cineon', CineonToneMapping],
['ACESFilmic', ACESFilmicToneMapping],
['Uncharted2', Uncharted2Tonemapping],
['AgX', AgXToneMapping],
].map(value => ({
label: value[0],
value: value[1],
}))),
onChange(TonemapPlugin.prototype.setDirty),
serialize()
], TonemapPlugin.prototype, "toneMapping", void 0);
__decorate([
uiToggle('Tonemap Background', (t) => ({ hidden: () => !t._viewer?.renderManager.gbufferTarget })),
matDefineBool('TONEMAP_BACKGROUND', undefined, true, TonemapPlugin.prototype.setDirty),
serialize()
], TonemapPlugin.prototype, "tonemapBackground", void 0);
__decorate([
onChange(TonemapPlugin.prototype.setDirty),
uiSlider('Exposure', [0, 2 * Math.PI], 0.01),
serialize()
], TonemapPlugin.prototype, "exposure", void 0);
__decorate([
uiSlider('Saturation', [0, 2], 0.01),
uniform({ propKey: 'toneMappingSaturation' }),
serialize()
], TonemapPlugin.prototype, "saturation", void 0);
__decorate([
uiSlider('Contrast', [0, 2], 0.01),
uniform({ propKey: 'toneMappingContrast' }),
serialize()
], TonemapPlugin.prototype, "contrast", void 0);
TonemapPlugin = __decorate([
uiFolderContainer('Tonemapping')
], TonemapPlugin);
export { TonemapPlugin };
//# sourceMappingURL=TonemapPlugin.js.map