@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
145 lines (144 loc) • 4.8 kB
JavaScript
"use strict";
import { isArray } from "./../../../core/Type";
import { BLEND_FUNCTION_MENU_OPTIONS } from "./../../../core/post/BlendFunction";
import { Vector2, Mesh, BufferGeometry, MeshBasicMaterial, Group } from "three";
import { TypedPostNode, PostParamOptions } from "./_Base";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { BlendFunction, GodRaysEffect, EffectPass, KernelSize } from "postprocessing";
import { KERNEL_SIZES, KERNEL_SIZE_MENU_OPTIONS } from "../../../core/post/KernelSize";
const tmpParent = new Group();
const tmpLightSource = new Mesh(new BufferGeometry(), new MeshBasicMaterial());
tmpParent.add(tmpLightSource);
function _updateLightSourceMaterial(material) {
material.depthWrite = false;
material.transparent = true;
}
function _findLightSource(scene, objectMask) {
let foundObject = void 0;
const objects = scene.objectsByMask(objectMask);
for (const object of objects) {
if (object.isMesh || object.isPoints) {
foundObject = object;
break;
}
}
return foundObject;
}
class GodRaysPostParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param objects to emit godrays from. Note that while the mask can resolve multiple objects, only the first mesh or points will be used */
this.objectMask = ParamConfig.STRING("*geo1*", {
objectMask: true
});
/** @param samples */
this.samples = ParamConfig.INTEGER(60, {
range: [1, 128],
rangeLocked: [true, false],
...PostParamOptions
});
/** @param density */
this.density = ParamConfig.FLOAT(0.96, {
range: [0, 1],
rangeLocked: [true, true],
...PostParamOptions
});
/** @param decay */
this.decay = ParamConfig.FLOAT(0.9, {
range: [0, 1],
rangeLocked: [true, true],
...PostParamOptions
});
/** @param weight */
this.weight = ParamConfig.FLOAT(0.4, {
range: [0, 1],
rangeLocked: [true, true],
...PostParamOptions
});
/** @param exposure */
this.exposure = ParamConfig.FLOAT(0.6, {
range: [0, 1],
rangeLocked: [true, true],
...PostParamOptions
});
/** @param blur */
this.blur = ParamConfig.BOOLEAN(1, {
...PostParamOptions
});
/** @param kernel size */
this.kernelSize = ParamConfig.INTEGER(KernelSize.LARGE, {
visibleIf: { blur: 1 },
...PostParamOptions,
...KERNEL_SIZE_MENU_OPTIONS
});
/** @param resolutionScale */
this.resolutionScale = ParamConfig.FLOAT(0.5, {
...PostParamOptions
});
/** @param effect opacity */
this.opacity = ParamConfig.FLOAT(1, {
range: [0, 1],
rangeLocked: [true, false],
...PostParamOptions
});
/** @param render mode */
this.blendFunction = ParamConfig.INTEGER(BlendFunction.SCREEN, {
...PostParamOptions,
...BLEND_FUNCTION_MENU_OPTIONS
});
}
}
const ParamsConfig = new GodRaysPostParamsConfig();
export class GodRaysPostNode extends TypedPostNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this._rendererSize = new Vector2();
}
static type() {
return "godRays";
}
createPass(context) {
context.renderer.getSize(this._rendererSize);
const effect = new GodRaysEffect(context.camera, tmpLightSource, {
blendFunction: BlendFunction.SCREEN,
kernelSize: KERNEL_SIZES[this.pv.kernelSize],
blur: this.pv.blur,
samples: this.pv.samples,
density: this.pv.density,
decay: this.pv.decay,
weight: this.pv.weight,
exposure: this.pv.exposure
});
const pass = new EffectPass(context.camera, effect);
this.updatePass(pass);
return pass;
}
updatePass(pass) {
const effect = pass.effects[0];
effect.godRaysMaterial.samples = this.pv.samples;
effect.godRaysMaterial.density = this.pv.density;
effect.godRaysMaterial.decay = this.pv.decay;
effect.godRaysMaterial.weight = this.pv.weight;
effect.godRaysMaterial.exposure = this.pv.exposure;
effect.blur = this.pv.blur;
effect.blurPass.blurMaterial.kernelSize = KERNEL_SIZES[this.pv.kernelSize];
effect.blurPass.resolution.scale = this.pv.resolutionScale;
effect.blendMode.opacity.value = this.pv.opacity;
effect.blendMode.blendFunction = this.pv.blendFunction;
const lightSource = _findLightSource(this.scene(), this.pv.objectMask);
if (lightSource) {
effect.lightSource = lightSource;
const material = lightSource.material;
if (isArray(material)) {
for (const m of material) {
_updateLightSourceMaterial(m);
}
} else {
_updateLightSourceMaterial(material);
}
} else {
effect.lightSource = tmpLightSource;
}
}
}