import { ObjectProxy } from '@uino/base-thing';
import { Utils } from '../common/Utils';
import { BaseComponent } from './BaseComponent';
const __ = {
private: Symbol('private'),
}
/**
* @class CameraPostEffectComponent
* The camera post effect compnent.
* @memberof THING
* @extends THING.BaseComponent
* @public
*/
class CameraPostEffectComponent extends BaseComponent {
/**
* The rendering effect by camera, some screen post effect(s) can be changed here.
*/
constructor() {
super();
this[__.private] = {};
let _private = this[__.private];
_private.needsRefresh = false;
/**
* Temporal super sampling
* @typedef {Object} TemporalSuperSampling
* @property {Boolean} enable True indicates enable it.
* @property {Number} size The max frames.
*/
_private.temporalSuperSampling = {
enable: false,
size: 30
};
/**
* Configuration about bloom post effect
* @typedef {Object} Bloom
* @property {Boolean} enable True indicates enable it.
* @property {Number} strength The intensity.
* @property {Number} radius The radius.
* @property {Number} threshold The threshold.
*/
_private.bloom = {
enable: false,
strength: 0.14,
radius: 0.4,
threshold: 0.7
};
/**
* Configuration about screen space ambient occulusion (SSAO).
* @typedef {Object} ScreenSpaceAmbientOcclusion
* @property {Boolean} enable True indicates enable it.
* @property {Number} radius The radius.
* Sampling radius in work space.
* Larger will produce more soft concat shadow.
* But also needs higher quality or it will have more obvious artifacts
* @property {String} quality Quality of SSAO. 'low'|'medium'|'high'|'ultra'.
* @property {Number} intensity The intensity.
* @property {Boolean} temporalFilter The temporal filter in temporal super sampling mode.
* @property {Boolean} ignoreTransparent if ignore transparent objects.
*/
_private.screenSpaceAmbientOcclusion = {
enable: false,
radius: 0.2,
quality: 'medium',
intensity: 0.8,
temporalFilter: true,
ignoreTransparent: false
};
/**
* Configuration about screen space reflection.
* @typedef {Object} ScreenSpaceReflection
* @property {Boolean} enable True indicates enable it.
* @property {Number} maxRayDistance
* @property {Number} pixelStride
* @property {Number} pixelStrideZCutoff
* @property {Number} screenEdgeFadeStart
* @property {Number} eyeFadeStart
* @property {Number} eyeFadeEnd
* @property {Number} minGlossiness
*/
_private.screenSpaceReflection = {
enable: false,
maxRayDistance: 200,
pixelStride: 16,
pixelStrideZCutoff: 50,
screenEdgeFadeStart: 0.9,
eyeFadeStart: 0.4,
eyeFadeEnd: 0.8,
minGlossiness: 0.2
};
/**
* Configuration about color correction.
* @typedef {Object} ColorCorrection
* @property {Boolean} enable True indicates enable it.
* @property {Number} exposure
* @property {Number} brightness
* @property {Number} contrast
* @property {Number} saturation
* @property {Number} gamma
*/
_private.colorCorrection = {
enable: true,
exposure: 0,
brightness: 0,
contrast: 1.1,
saturation: 1.1,
gamma: 1
};
/**
* Configuration about dof.
* @typedef {Object} Dof
* @property {Boolean} enable True indicates enable it.
* @property {Number} focalDepth
* @property {Number} focalLength
* @property {Number} fstop
* @property {Number} maxblur
* @property {Number} threshold
* @property {Number} gain
* @property {Number} bias
* @property {Number} dithering
*/
_private.dof = {
enable: false,
focalDepth: 1,
focalLength: 24,
fstop: 0.9,
maxblur: 1.0,
threshold: 0.9,
gain: 1.0,
bias: 0.5,
dithering: 0.0001
};
/**
* Configuration about vignetting.
* @typedef {Object} Vignetting
* @property {Boolean} enable True indicates enable it.
* @property {Array<Number>} color The color, only for color type
* @property {Number} offset The offset.
*/
_private.vignetting = {
enable: false,
color: [0, 0, 0],
offset: 1.5
};
/**
* Configuration about blur edge.
* @typedef {Object} BlurEdge
* @property {Boolean} enable True indicates enable it.
* @property {Number} offset The offset.
*/
_private.blurEdge = {
enable: false,
offset: 1.0
};
/**
* Configuration about film effect.
* @typedef {Object} Film
* @property {Boolean} enable True indicates enable it.
* @property {Boolean} grayscale
* @property {Number} noiseIntensity
* @property {Number} scanlinesIntensity
* @property {Number} scanlinesCount
*/
_private.film = {
enable: false,
grayscale: false,
noiseIntensity: 0.35,
scanlinesIntensity: 0,
scanlinesCount: 2048
};
/**
* Chromatic aberration.
* @typedef {Object} ChromaticAberration
* @property {Boolean} enable True indicates enable it.
* @property {Number} chromaFactor
*/
_private.chromaticAberration = {
enable: false,
chromaFactor: 0.025
};
/**
* Configuration about FXAA.
* @typedef {Object} FXAA
* @property {Boolean} enable True indicates enable it.
*/
_private.FXAA = {
enable: false
};
/**
* Configuration about MSAA.
* @typedef {Object} MSAA
* @property {Boolean} enable True indicates enable it.
*/
_private.MSAA = {
enable: true
};
_private.onChange = null;
_private.objectProxy = new ObjectProxy({
data: {
enable: true,
bloom: _private.bloom,
screenSpaceAmbientOcclusion: _private.screenSpaceAmbientOcclusion,
screenSpaceReflection: _private.screenSpaceReflection,
colorCorrection: _private.colorCorrection,
dof: _private.dof,
vignetting: _private.vignetting,
blurEdge: _private.blurEdge,
film: _private.film,
chromaticAberration: _private.chromaticAberration,
FXAA: _private.FXAA,
MSAA: _private.MSAA,
temporalSuperSampling: _private.temporalSuperSampling,
},
onConvertValue: function (type, value) {
if (type == 'color') {
return Utils.parseColor(value, [1, 1, 1]);
}
},
onChange: function (ev) {
_private.needsRefresh = true;
if (_private.onChange) {
_private.onChange(ev);
}
}
});
// Refresh effect by current config
this._refresh();
// Show config always
Object.defineProperty(this, 'customFormatters', {
enumerable: false,
configurable: false,
get: function () {
return ['object', { object: _private.objectProxy.dataProxy }];
}
});
}
// #region Private Functions
_refresh() {
let object = this.object;
if (!object) {
return;
}
let _private = this[__.private];
if (!_private.needsRefresh) {
return;
}
_private.needsRefresh = false;
object.node.setPostEffect({
temporalSuperSampling: _private.temporalSuperSampling,
postEffect: {
enable: _private.objectProxy.dataProxy.enable,
bloom: _private.bloom,
screenSpaceAmbientOcclusion: _private.screenSpaceAmbientOcclusion,
screenSpaceReflection: _private.screenSpaceReflection,
colorCorrection: _private.colorCorrection,
dof: _private.dof,
vignetting: _private.vignetting,
blurEdge: _private.blurEdge,
film: _private.film,
chromaticAberration: _private.chromaticAberration,
FXAA: _private.FXAA,
MSAA: _private.MSAA,
}
});
}
// #endregion
// #region BaseComponent Overrides
onAdd(object) {
super.onAdd(object);
// Refresh config before render if needed
this.app.addBeforeRenderCallback(this._onBeforeRenderCallback = () => {
this._refresh();
});
}
onRemove() {
let _private = this[__.private];
_private.objectProxy.dispose();
this.app.removeBeforeRenderCallback(this._onBeforeRenderCallback);
super.onRemove();
}
onCopy(component) {
this.config = component.config;
}
// #endregion
/**
* Enable/Disable effect.
* @type {Boolean}
* @example
* let app = THING.App.current
* app.camera.postEffect.enable = false;
* // @expect(app.camera.postEffect.enable == false)
* @public
*/
get enable() {
let _private = this[__.private];
return _private.objectProxy.dataProxy.enable;
}
set enable(value) {
let _private = this[__.private];
if (_private.objectProxy.dataProxy.enable == value) {
return;
}
_private.objectProxy.dataProxy.enable = value;
this._refresh();
}
/**
* Get temporal super sampling.
* @type {TemporalSuperSampling}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.temporalSuperSampling.enable = true;
* // @expect(app.camera.postEffect.temporalSuperSampling.enable == true)
* @public
*/
get temporalSuperSampling() {
return this[__.private].objectProxy.dataProxy.temporalSuperSampling;
}
/**
* Get bloom.
* @type {Bloom}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.bloom.enable = true;
* // @expect(app.camera.postEffect.bloom.enable == true)
* @public
*/
get bloom() {
return this[__.private].objectProxy.dataProxy.bloom;
}
/**
* Get screen space ambient occlusion.
* @type {ScreenSpaceAmbientOcclusion}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.screenSpaceAmbientOcclusion.enable = true;
* // @expect(app.camera.postEffect.screenSpaceAmbientOcclusion.enable == true)
* @public
*/
get screenSpaceAmbientOcclusion() {
return this[__.private].objectProxy.dataProxy.screenSpaceAmbientOcclusion;
}
/**
* Get screen space reflection.
* @type {ScreenSpaceReflection}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.screenSpaceReflection.enable = true;
* // @expect(app.camera.postEffect.screenSpaceReflection.enable == true)
* @public
*/
get screenSpaceReflection() {
return this[__.private].objectProxy.dataProxy.screenSpaceReflection;
}
/**
* Get color correction.
* @type {ColorCorrection}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.colorCorrection.enable = true;
* // @expect(app.camera.postEffect.colorCorrection.enable == true)
* @public
*/
get colorCorrection() {
return this[__.private].objectProxy.dataProxy.colorCorrection;
}
/**
* Get dof.
* @type {Dof}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.dof.enable = true;
* // @expect(app.camera.postEffect.dof.enable == true)
* @public
*/
get dof() {
return this[__.private].objectProxy.dataProxy.dof;
}
/**
* Get vignetting.
* @type {Vignetting}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.vignetting.enable = true;
* // @expect(app.camera.postEffect.vignetting.enable == true)
* @public
*/
get vignetting() {
return this[__.private].objectProxy.dataProxy.vignetting;
}
/**
* Get blur edge.
* @type {BlurEdge}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.blurEdge.enable = true;
* // @expect(app.camera.postEffect.blurEdge.enable == true)
* @public
*/
get blurEdge() {
return this[__.private].objectProxy.dataProxy.blurEdge;
}
/**
* Get film.
* @type {Film}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.film.enable = true;
* // @expect(app.camera.postEffect.film.enable == true)
* @public
*/
get film() {
return this[__.private].objectProxy.dataProxy.film;
}
/**
* Get chromatic aberration.
* @type {ChromaticAberration}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.chromaticAberration.enable = true;
* // @expect(app.camera.postEffect.chromaticAberration.enable == true)
* @public
*/
get chromaticAberration() {
return this[__.private].objectProxy.dataProxy.chromaticAberration;
}
/**
* Get FXAA.
* @type {FXAA}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.FXAA.enable = true;
* // @expect(app.camera.postEffect.FXAA.enable == true)
* @public
*/
get FXAA() {
return this[__.private].objectProxy.dataProxy.FXAA;
}
/**
* Get MSAA.
* @type {MSAA}
* @example
* let app = THING.App.current
* app.camera.postEffect.config.MSAA.enable = false;
* // @expect(app.camera.postEffect.MSAA.enable == false)
* @public
*/
get MSAA() {
return this[__.private].objectProxy.dataProxy.MSAA;
}
/**
* Configuration about post effect.
* @typedef {Object} PostEffectInfo
* @property {Boolean} enable True indicates enable it.
* @property {Bloom} bloom The bloom effect.
* @property {ScreenSpaceAmbientOcclusion} screenSpaceAmbientOcclusion The screen space ambient occlusion effect.
* @property {ScreenSpaceReflection} screenSpaceReflection The screen space reflection effect.
* @property {ColorCorrection} colorCorrection The color correction effect.
* @property {Dof} dof The dof effect.
* @property {Vignetting} vignetting The vignetting effect.
* @property {BlurEdge} blurEdge The blur edge effect.
* @property {Film} film The film effect.
* @property {ChromaticAberration} chromaticAberration The chromatic aberration effect.
* @property {FXAA} FXAA The FXAA effect.
* @property {MSAA} MSAA The MSAA effect.
* @property {TemporalSuperSampling} temporalSuperSampling The temporal super sampling effect.
*/
/**
* Get/Set config.
* @type {PostEffectInfo}
* @example
* let app = THING.App.current
* app.camera.postEffect.config = {
* FXAA: {enable: true}
* };
* // @expect(app.camera.postEffect.config.FXAA.enable == true)
* @public
*/
get config() {
return this[__.private].objectProxy.dataProxy;
}
set config(value = {}) {
let _private = this[__.private];
let to = _private.objectProxy.dataProxy;
if (Utils.isValid(value.enable)) {
to.enable = value.enable;
}
Utils.mergeObject(to.bloom, value.bloom, true);
Utils.mergeObject(to.screenSpaceAmbientOcclusion, value.screenSpaceAmbientOcclusion, true);
Utils.mergeObject(to.screenSpaceReflection, value.screenSpaceReflection, true);
Utils.mergeObject(to.colorCorrection, value.colorCorrection, true);
Utils.mergeObject(to.dof, value.dof, true);
Utils.mergeObject(to.vignetting, value.vignetting, true);
Utils.mergeObject(to.blurEdge, value.blurEdge, true);
Utils.mergeObject(to.film, value.film, true);
Utils.mergeObject(to.chromaticAberration, value.chromaticAberration, true);
Utils.mergeObject(to.FXAA, value.FXAA, true);
Utils.mergeObject(to.MSAA, value.MSAA, true);
Utils.mergeObject(to.temporalSuperSampling, value.temporalSuperSampling, true);
}
/**
* Get/Set when change callback function.
* @type {Function}
* @private
*/
get onChange() {
let _private = this[__.private];
return _private.onChange;
}
set onChange(value) {
let _private = this[__.private];
_private.onChange = value;
}
}
export { CameraPostEffectComponent }