UNPKG

@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
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 */ @serializable(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 */ @serializable(VolumeParameter) readonly intensity: VolumeParameter = new VolumeParameter(1); /** * Scatter value. The higher the value, the more the bloom will scatter. * @default 0.7 */ @serializable(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);