UNPKG

@polygonjs/polygonjs

Version:

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

216 lines (215 loc) 7.28 kB
"use strict"; import { ParamConfig } from "../../engine/nodes/utils/params/ParamsConfig"; import { Group, Mesh, Color, Vector2, DirectionalLight, LineBasicMaterial, BufferGeometry, Float32BufferAttribute, Line } from "three"; import { CoreCameraHelper } from "../helpers/CoreCameraHelper"; import { ObjectType, registerObjectType } from "../geometry/Constant"; export const DEFAULT_DIRECTIONAL_LIGHT_PARAMS = { color: new Color(1, 1, 1), intensity: 1, distance: 100, // showHelper: false, name: "directionalLight", // castShadow: false, shadowAutoUpdate: true, shadowUpdateOnNextRender: false, shadowRes: new Vector2(1024, 1024), shadowSize: new Vector2(2, 2), shadowBias: 1e-3, shadowRadius: 0, debugShadow: false, // raymarchingPenumbra: 0, // keep as 0 by default since it's more performant raymarchingShadowBiasAngle: 0.01, raymarchingShadowBiasDistance: 0.1 }; const DEFAULT = DEFAULT_DIRECTIONAL_LIGHT_PARAMS; export function DirectionalLightParamConfig(Base) { return class Mixin extends Base { constructor() { super(...arguments); this.light = ParamConfig.FOLDER(); /** @param light color */ this.color = ParamConfig.COLOR(DEFAULT.color.toArray(), { // conversion: ColorConversion.SRGB_TO_LINEAR, }); /** @param light intensity */ this.intensity = ParamConfig.FLOAT(DEFAULT.intensity, { range: [0, 2], rangeLocked: [true, false] }); /** @param light distance */ this.distance = ParamConfig.FLOAT(DEFAULT.distance, { range: [0, 100], rangeLocked: [true, false] }); // helper /** @param toggle to show helper */ this.showHelper = ParamConfig.BOOLEAN(DEFAULT.showHelper); /** @param light name */ this.name = ParamConfig.STRING("`$OS`"); // shadows this.shadow = ParamConfig.FOLDER(); /** @param toggle on to cast shadows */ this.castShadow = ParamConfig.BOOLEAN(DEFAULT.castShadow); /** @param toggle off if the shadows do not need to be regenerated */ this.shadowAutoUpdate = ParamConfig.BOOLEAN(DEFAULT.shadowAutoUpdate, { visibleIf: { castShadow: 1 } }); /** @param press button to update the shadows on next render */ this.shadowUpdateOnNextRender = ParamConfig.BOOLEAN(DEFAULT.shadowUpdateOnNextRender, { visibleIf: { castShadow: 1, shadowAutoUpdate: 0 } }); /** @param shadow resolution */ this.shadowRes = ParamConfig.VECTOR2(DEFAULT.shadowRes.toArray(), { visibleIf: { castShadow: true } }); /** @param shadow size */ this.shadowSize = ParamConfig.VECTOR2(DEFAULT.shadowSize.toArray(), { visibleIf: { castShadow: true } }); /** @param shadow bias */ this.shadowBias = ParamConfig.FLOAT(DEFAULT.shadowBias, { visibleIf: { castShadow: true }, range: [-0.01, 0.01], rangeLocked: [false, false] }); /** @param shadows radius. This only has effect when setting the ROP/WebGLRenderer's shadowMapType to VSM */ this.shadowRadius = ParamConfig.FLOAT(DEFAULT.shadowRadius, { visibleIf: { castShadow: 1 }, range: [0, 10], rangeLocked: [true, false] }); /** @param display shadow on a plane behind the light */ // debugShadow = ParamConfig.BOOLEAN(DEFAULT.debugShadow, { // visibleIf: {castShadow: 1}, // }); // raymarching this.raymarching = ParamConfig.FOLDER(); /** @param this affects the shadows cast inside raymarchingBuilder materials */ this.raymarchingPenumbra = ParamConfig.FLOAT(DEFAULT.raymarchingPenumbra); /** @param shadow bias */ this.raymarchingShadowBiasAngle = ParamConfig.FLOAT(DEFAULT.raymarchingShadowBiasAngle, { range: [0, 1], rangeLocked: [true, false] }); /** @param shadow bias */ this.raymarchingShadowBiasDistance = ParamConfig.FLOAT(DEFAULT.raymarchingShadowBiasDistance, { range: [0, 1], rangeLocked: [true, false] }); } }; } export class DirectionalLightContainer extends Group { constructor(options, nodeName) { super(); this.nodeName = nodeName; this._light = new DirectionalLight(); this._target = this._light.target; this.showHelper = false; this.matrixAutoUpdate = false; registerObjectType({ type: ObjectType.DIRECTIONAL_LIGHT, checkFunc: (o) => { if (o.isDirectionalLight) { return ObjectType.DIRECTIONAL_LIGHT; } }, ctor: DirectionalLight, humanName: "DirectionalLight" }); this.showHelper = options.showHelper; this._light.position.set(0, 0, 1); this._light.updateMatrix(); this._target.updateMatrix(); this._light.matrixAutoUpdate = false; this._target.matrixAutoUpdate = false; this.name = `DirectionalLightContainer_${nodeName}`; this._light.name = `DirectionalLight_${nodeName}`; this._target.name = `DirectionalLightTarget_${nodeName}`; this.add(this._light); this.add(this._target); this.updateHelper(); } light() { return this._light; } copy(source, recursive) { this._light.copy(source.light(), false); super.copy(source, false); this._light.target = this._target; this.updateHelper(); return this; } clone(recursive) { const cloned = new DirectionalLightContainer({ showHelper: this.showHelper }, this.nodeName); cloned.copy(this); return cloned; } updateHelper() { if (this.showHelper) { this.__helper__ = this.__helper__ || new CoreDirectionalLightHelper(this); this.add(this.__helper__.object); this.__helper__.update(); } else { if (this.__helper__) { this.remove(this.__helper__.object); } } } } export class CoreDirectionalLightHelper { constructor(container) { this.container = container; this.object = new Mesh(); this._lineMaterial = new LineBasicMaterial(); this._square = new Line(); this.createAndBuildObject(); } createAndBuildObject() { this.buildHelper(); this.update(); } buildHelper() { const light = this.container.light(); const geometry = new BufferGeometry(); const size = 1; geometry.setAttribute( "position", new Float32BufferAttribute( [-size, size, 0, size, size, 0, size, -size, 0, -size, -size, 0, -size, size, 0], 3 ) ); this._square.geometry = geometry; this._square.material = this._lineMaterial; this._square.updateMatrix(); this._square.matrixAutoUpdate = false; this.object.add(this._square); this._cameraHelper = new CoreCameraHelper(light.shadow.camera); this._cameraHelper.updateMatrix(); this._cameraHelper.matrixAutoUpdate = false; this.object.add(this._cameraHelper); this.object.name = `CoreDirectionalLightHelper_${this.container.nodeName}`; this._square.name = `CoreDirectionalLightHelperSquare_${this.container.nodeName}`; this._cameraHelper.name = `CoreDirectionalLightHelperCameraHelper_${this.container.nodeName}`; } update() { this.object.updateMatrix(); this._cameraHelper.update(); this._lineMaterial.color.copy(this.container.light().color); } }