@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
169 lines • 7.22 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;
};
import { serializable } from "../../engine/engine_serialization.js";
import { getParam } from "../../engine/engine_utils.js";
import { Component } from "../Component.js";
import { getPostProcessingManager } from "./utils.js";
import { VolumeParameter } from "./VolumeParameter.js";
const debug = getParam("debugpost");
/**
* PostProcessingEffect is a base class for post processing effects that can be applied to the scene.
* To create a custom post processing effect, extend this class and override the `onCreateEffect` method and call `registerCustomEffectType` to make it available in the editor.
* @example
* ```typescript
* import { EdgeDetectionMode, SMAAEffect, SMAAPreset } from "postprocessing";
* export class Antialiasing extends PostProcessingEffect {
* get typeName(): string {
* return "Antialiasing";
* }
* @serializable(VolumeParameter)
* preset!: VolumeParameter = new VolumeParameter();
* onCreateEffect(): EffectProviderResult {
* const effect = new SMAAEffect({
* preset: SMAAPreset.HIGH,
* edgeDetectionMode: EdgeDetectionMode.DEPTH
* });
* this.preset.onValueChanged = (newValue) => {
* effect.applyPreset(newValue);
* };
* return effect;
* }
* }
* registerCustomEffectType("Antialiasing", Antialiasing)
* ```
*
* @category Effects
* @group Components
*/
export class PostProcessingEffect extends Component {
get isPostProcessingEffect() { return true; }
/**
* The order of this effect. The higher the order the later the effect will be applied in the post processing stack.
* This can be used to control the order of effects when multiple effects are applied.
* It is recommended to use the PostProcessingEffectOrder constant to order your custom effects before or after built-in effects.
* @default `undefined` (no specific order set, will be applied in the order of registration)
*
* @example
* ```typescript
* import { PostProcessingEffectOrder } from "@needle-tools/engine"
*
* export class MyCustomEffect extends PostProcessingEffect {
* order: PostProcessingEffectOrder.Bloom + 1; // render after bloom
* // This will ensure that the effect is applied after the bloom effect in the post processing stack.
* // ... the rest of your effect code
* }
* ```
*/
order = undefined;
constructor(params = undefined) {
super();
if (params) {
for (const key of Object.keys(params)) {
const value = params[key];
const param = this[key];
if (param instanceof VolumeParameter) {
param.initialize(value);
}
// allow assigning values to properties that are not VolumeParameters
// this is useful when effects are created in code
else if (param !== undefined) {
this[key] = value;
}
}
}
}
/**
* Whether the effect is active or not. Prefer using `enabled` instead.
* @deprecated
*/
active = true;
_manager = null;
onEnable() {
super.onEnable();
if (debug)
console.warn("Enable", this.constructor.name + (!this.__internalDidAwakeAndStart ? " (awake)" : ""));
// Dont override the serialized value by enabling (we could also just disable this component / map enabled to active)
if (this.__internalDidAwakeAndStart)
this.active = true;
this.onEffectEnabled();
}
onDisable() {
super.onDisable();
if (debug)
console.warn("Disable", this.constructor.name);
this._manager?.removeEffect(this);
this.active = false;
}
onEffectEnabled(manager) {
if (manager && manager.isPostProcessingManager === true)
this._manager = manager;
else if (!this._manager)
this._manager = getPostProcessingManager(this);
this._manager.addEffect(this);
this._manager.dirty = true;
}
/** override to initialize bindings on parameters */
init() { }
/** previously created effect (if any) */
_result;
_postprocessingContext = null;
get postprocessingContext() { return this._postprocessingContext; }
/** Apply post settings. Make sure to call super.apply() if you also create an effect */
apply(ctx) {
this._postprocessingContext = ctx;
if (!this._result) {
this.initParameters();
this._result = this.onCreateEffect?.call(this);
}
// TODO: calling this twice because otherwise the Postprocessing sample doesnt look correct. Need to investigate which effect is causing this (init parameters should be refactored either way https://linear.app/needle/issue/NE-5182)
if (this._result) {
this.initParameters();
}
return this._result;
}
/** Reset previously set values (e.g. when adjusting settings on the renderer like Tonemapping) */
unapply() { }
dispose() {
if (debug)
console.warn("DISPOSE", this);
if (this._result) {
if (Array.isArray(this._result)) {
this._result.forEach(r => r.dispose());
}
else {
this._result.dispose();
}
}
this._result = undefined;
}
initParameters() {
// Automatically call init on all VolumeParameter properties
// This will enforce the valueProcessor and onValueChanged to be called
const keys = Object.keys(this);
for (const key of keys) {
const value = this[key];
if (value instanceof VolumeParameter) {
value.__init();
}
}
}
// TODO this is currently not used for post processing effects that are part of Volume stacks,
// since these handle that already.
onEditorModification(modification) {
// Handle a property modification if the property is a VolumeParameter and the modification is just a plain value
const key = modification.propertyName;
if (this[key] instanceof VolumeParameter) {
const value = modification.value;
this[key].value = value;
return true;
}
}
}
__decorate([
serializable()
], PostProcessingEffect.prototype, "active", void 0);
//# sourceMappingURL=PostProcessingEffect.js.map