@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.
117 lines (102 loc) • 4.33 kB
text/typescript
import { BloomEffect as _BloomEffect, EffectAttribute } from "postprocessing";
import { MathUtils } from "three";
import { MODULES } from "../../../engine/engine_modules.js";
import { serializable } from "../../../engine/engine_serialization.js";
import { PostProcessingEffect } from "../PostProcessingEffect.js";
import { VolumeParameter } from "../VolumeParameter.js";
import { registerCustomEffectType } from "../VolumeProfile.js";
/**
* Bloom can be used to make bright areas in the scene glow.
* @link Sample https://engine.needle.tools/samples/postprocessing
* @example
* ```typescript
* const bloom = new Bloom();
* bloom.intensity.value = 1.5;
* bloom.threshold.value = 0.5;
* bloom.scatter.value = 0.5;
* volume.add(bloom);
* ```
*
* @category Effects
* @group Components
*/
export class BloomEffect extends PostProcessingEffect {
/** Whether to use selective bloom by default */
static useSelectiveBloom = false;
get typeName() {
return "Bloom";
}
/**
* The bloom threshold controls at what brightness level the bloom effect will be applied.
* A higher value means the bloom will be applied to brighter areas or lights only
* @default 0.9
*/
(VolumeParameter)
readonly threshold: VolumeParameter = new VolumeParameter(.9);
/**
* Intensity of the bloom effect. A higher value will increase the intensity of the bloom effect.
* @default 1
*/
(VolumeParameter)
readonly intensity: VolumeParameter = new VolumeParameter(1);
/**
* Scatter value. The higher the value, the more the bloom will scatter.
* @default 0.7
*/
(VolumeParameter)
readonly scatter: VolumeParameter = new VolumeParameter(.7);
/**
* Set to true to use selective bloom when the effect gets created.
* @default false
*/
selectiveBloom?: boolean;
init() {
this.threshold.valueProcessor = (v: number) => v;
this.intensity.valueProcessor = (v: number) => v;
this.scatter.valueProcessor = (v: number) => v;
}
onCreateEffect() {
let bloom: _BloomEffect;
if (this.selectiveBloom == undefined) {
this.selectiveBloom = BloomEffect.useSelectiveBloom;
}
if (this.selectiveBloom) {
// https://github.com/pmndrs/postprocessing/blob/64d2829f014cfec97a46bf3c109f3abc55af0715/demo/src/demos/BloomDemo.js#L265
const selectiveBloom = bloom = new MODULES.POSTPROCESSING.MODULE.SelectiveBloomEffect(this.context.scene, this.context.mainCamera!, {
blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.ADD,
mipmapBlur: true,
luminanceThreshold: this.threshold.value,
luminanceSmoothing: this.scatter.value,
radius: 0.85, // default value
intensity: this.intensity.value,
});
selectiveBloom.inverted = true;
}
else {
bloom = new MODULES.POSTPROCESSING.MODULE.BloomEffect({
blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.ADD,
mipmapBlur: true,
luminanceThreshold: this.threshold.value,
luminanceSmoothing: this.scatter.value,
radius: 0.85, // default value
intensity: this.intensity.value,
});
}
this.intensity.onValueChanged = newValue => {
bloom!.intensity = newValue;
};
this.threshold.onValueChanged = newValue => {
// for some reason the threshold needs to be gamma-corrected
bloom!.luminanceMaterial.threshold = Math.pow(newValue, 2.2);
};
this.scatter.onValueChanged = newValue => {
bloom!.luminancePass.enabled = true;
bloom!.luminanceMaterial.smoothing = newValue;
if (bloom["mipmapBlurPass"])
// heuristic so it looks similar to "scatter" in other engines
bloom!["mipmapBlurPass"].radius = MathUtils.lerp(0.1, 0.9, newValue);
};
return bloom;
}
}
registerCustomEffectType("Bloom", BloomEffect);