UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

145 lines (144 loc) 4.8 kB
"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; } } }