UNPKG

polygonjs-engine

Version:

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

166 lines (152 loc) 5.04 kB
/** * Adds a depth of field effect * * */ import {TypedPostProcessNode, TypedPostNodeContext, PostParamOptions} from './_Base'; import {BokehPass2} from '../../../modules/core/post_process/BokehPass2'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {PerspectiveCamera} from 'three/src/cameras/PerspectiveCamera'; import {PerspectiveCameraObjNode} from '../obj/PerspectiveCamera'; import {CoreGraphNode} from '../../../core/graph/CoreGraphNode'; class DepthOfFieldPostParamsConfig extends NodeParamsConfig { focalDepth = ParamConfig.FLOAT(10, { range: [0, 50], rangeLocked: [true, false], step: 0.001, ...PostParamOptions, }); fStep = ParamConfig.FLOAT(10, { range: [0.1, 22], rangeLocked: [true, true], ...PostParamOptions, }); maxBlur = ParamConfig.FLOAT(2, { range: [0, 10], rangeLocked: [true, false], ...PostParamOptions, }); vignetting = ParamConfig.BOOLEAN(0, { ...PostParamOptions, }); depthBlur = ParamConfig.BOOLEAN(0, { ...PostParamOptions, }); threshold = ParamConfig.FLOAT(0.5, { range: [0, 1], rangeLocked: [true, true], step: 0.001, ...PostParamOptions, }); gain = ParamConfig.FLOAT(1, { range: [0, 100], rangeLocked: [true, true], step: 0.001, ...PostParamOptions, }); bias = ParamConfig.FLOAT(1, { range: [0, 3], rangeLocked: [true, true], step: 0.001, ...PostParamOptions, }); fringe = ParamConfig.FLOAT(0.7, { range: [0, 5], rangeLocked: [true, false], step: 0.001, ...PostParamOptions, }); noise = ParamConfig.BOOLEAN(0, { ...PostParamOptions, }); dithering = ParamConfig.FLOAT(0, { range: [0, 0.001], rangeLocked: [true, true], step: 0.0001, ...PostParamOptions, }); pentagon = ParamConfig.BOOLEAN(0, { ...PostParamOptions, }); rings = ParamConfig.INTEGER(3, { range: [1, 8], rangeLocked: [true, true], ...PostParamOptions, }); samples = ParamConfig.INTEGER(4, { range: [1, 13], rangeLocked: [true, true], ...PostParamOptions, }); clearColor = ParamConfig.COLOR([1, 1, 1], { ...PostParamOptions, }); } const ParamsConfig = new DepthOfFieldPostParamsConfig(); export class DepthOfFieldPostNode extends TypedPostProcessNode<BokehPass2, DepthOfFieldPostParamsConfig> { params_config = ParamsConfig; static type() { return 'depthOfField'; } static saturate(x: number) { return Math.max(0, Math.min(1, x)); } static linearize(depth: number, near: number, far: number) { var zfar = far; var znear = near; return (-zfar * znear) / (depth * (zfar - znear) - zfar); } static smoothstep(near: number, far: number, depth: number) { var x = this.saturate((depth - near) / (far - near)); return x * x * (3 - 2 * x); } protected _create_pass(context: TypedPostNodeContext) { const camera = context.camera; if ((camera as PerspectiveCamera).isPerspectiveCamera) { const camera_node = context.camera_node as PerspectiveCameraObjNode; if (camera_node) { const pass = new BokehPass2(this, context.scene, camera_node.object, context.resolution); this.update_pass(pass); // TODO: add a dispose to get rid of those connections when the node is deleted // or when the camera is deleted // and maybe the graph node should be on the pass itself? // so that it can be called when we call .dispose() on it? const core_graph_node = new CoreGraphNode(this.scene(), 'DOF'); core_graph_node.addGraphInput(camera_node.p.near); core_graph_node.addGraphInput(camera_node.p.far); core_graph_node.addGraphInput(camera_node.p.fov); core_graph_node.addGraphInput(this.p.focalDepth); core_graph_node.addPostDirtyHook('post/DOF', () => { this.update_pass_from_camera_node(pass, camera_node); }); return pass; } } } update_pass_from_camera_node(pass: BokehPass2, camera: PerspectiveCameraObjNode) { pass.update_camera_uniforms_with_node(this, camera.object); } update_pass(pass: BokehPass2) { pass.bokeh_uniforms['fstop'].value = this.pv.fStep; pass.bokeh_uniforms['maxblur'].value = this.pv.maxBlur; pass.bokeh_uniforms['threshold'].value = this.pv.threshold; pass.bokeh_uniforms['gain'].value = this.pv.gain; pass.bokeh_uniforms['bias'].value = this.pv.bias; pass.bokeh_uniforms['fringe'].value = this.pv.fringe; pass.bokeh_uniforms['dithering'].value = this.pv.dithering; // booleans pass.bokeh_uniforms['noise'].value = this.pv.noise ? 1 : 0; pass.bokeh_uniforms['pentagon'].value = this.pv.pentagon ? 1 : 0; pass.bokeh_uniforms['vignetting'].value = this.pv.vignetting ? 1 : 0; pass.bokeh_uniforms['depthblur'].value = this.pv.depthBlur ? 1 : 0; // debug pass.bokeh_uniforms['shaderFocus'].value = 0; pass.bokeh_uniforms['showFocus'].value = 0; pass.bokeh_uniforms['manualdof'].value = 0; pass.bokeh_uniforms['focusCoords'].value.set(0.5, 0.5); pass.bokeh_material.defines['RINGS'] = this.pv.rings; pass.bokeh_material.defines['SAMPLES'] = this.pv.samples; pass.bokeh_material.needsUpdate = true; pass.clear_color.copy(this.pv.clearColor); } }