UNPKG

@polygonjs/polygonjs

Version:

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

265 lines (242 loc) 7.9 kB
import {ParamConfig} from '../../engine/nodes/utils/params/ParamsConfig'; import {Constructor, Number3} from '../../types/GlobalTypes'; // import {ColorConversion} from '../Color'; import { Group, Mesh, Color, Vector2, DirectionalLight, LineBasicMaterial, BufferGeometry, Float32BufferAttribute, Line, } from 'three'; import {DefaultOperationParams} from '../operations/_Base'; // import {CameraHelper} from 'three'; import {CoreCameraHelper} from '../helpers/CoreCameraHelper'; import {ObjectType, registerObjectType} from '../geometry/Constant'; export interface DirectionalLightParams extends DefaultOperationParams { color: Color; intensity: number; distance: number; // showHelper: boolean; name: string; // castShadow: boolean; shadowAutoUpdate: boolean; shadowUpdateOnNextRender: boolean; shadowRes: Vector2; shadowSize: Vector2; shadowBias: number; shadowRadius: number; // debugShadow: boolean; // removed (see spotlight for explanation) // raymarchingPenumbra: number; raymarchingShadowBiasAngle: number; raymarchingShadowBiasDistance: number; } export const DEFAULT_DIRECTIONAL_LIGHT_PARAMS: DirectionalLightParams = { 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: 0.001, 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<TBase extends Constructor>(Base: TBase) { return class Mixin extends Base { light = ParamConfig.FOLDER(); /** @param light color */ color = ParamConfig.COLOR(DEFAULT.color.toArray() as Number3, { // conversion: ColorConversion.SRGB_TO_LINEAR, }); /** @param light intensity */ intensity = ParamConfig.FLOAT(DEFAULT.intensity, { range: [0, 2], rangeLocked: [true, false], }); /** @param light distance */ distance = ParamConfig.FLOAT(DEFAULT.distance, { range: [0, 100], rangeLocked: [true, false], }); // helper /** @param toggle to show helper */ showHelper = ParamConfig.BOOLEAN(DEFAULT.showHelper); /** @param light name */ name = ParamConfig.STRING('`$OS`'); // shadows shadow = ParamConfig.FOLDER(); /** @param toggle on to cast shadows */ castShadow = ParamConfig.BOOLEAN(DEFAULT.castShadow); /** @param toggle off if the shadows do not need to be regenerated */ shadowAutoUpdate = ParamConfig.BOOLEAN(DEFAULT.shadowAutoUpdate, { visibleIf: {castShadow: 1}, }); /** @param press button to update the shadows on next render */ shadowUpdateOnNextRender = ParamConfig.BOOLEAN(DEFAULT.shadowUpdateOnNextRender, { visibleIf: {castShadow: 1, shadowAutoUpdate: 0}, }); /** @param shadow resolution */ shadowRes = ParamConfig.VECTOR2(DEFAULT.shadowRes.toArray(), { visibleIf: {castShadow: true}, }); /** @param shadow size */ shadowSize = ParamConfig.VECTOR2(DEFAULT.shadowSize.toArray(), { visibleIf: {castShadow: true}, }); /** @param shadow bias */ 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 */ 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 raymarching = ParamConfig.FOLDER(); /** @param this affects the shadows cast inside raymarchingBuilder materials */ raymarchingPenumbra = ParamConfig.FLOAT(DEFAULT.raymarchingPenumbra); /** @param shadow bias */ raymarchingShadowBiasAngle = ParamConfig.FLOAT(DEFAULT.raymarchingShadowBiasAngle, { range: [0, 1], rangeLocked: [true, false], }); /** @param shadow bias */ raymarchingShadowBiasDistance = ParamConfig.FLOAT(DEFAULT.raymarchingShadowBiasDistance, { range: [0, 1], rangeLocked: [true, false], }); }; } export interface DirectionalLightContainerParams { showHelper: boolean; } export class DirectionalLightContainer extends Group { private _light = new DirectionalLight(); private _target = this._light.target; public showHelper = false; public override matrixAutoUpdate = false; constructor(options: DirectionalLightContainerParams, public readonly nodeName: string) { super(); registerObjectType({ type: ObjectType.DIRECTIONAL_LIGHT, checkFunc: (o) => { if ((o as DirectionalLight).isDirectionalLight) { return ObjectType.DIRECTIONAL_LIGHT; } }, ctor: DirectionalLight, humanName: 'DirectionalLight', }); this.showHelper = options.showHelper; // set light pos to 0,0,1 // in order to have it face z axis 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; } override copy(source: this, recursive?: boolean): this { this._light.copy(source.light(), false); super.copy(source, false); this._light.target = this._target; this.updateHelper(); return this as this; } override clone(recursive?: boolean): this { const cloned = new DirectionalLightContainer({showHelper: this.showHelper}, this.nodeName); cloned.copy(this); return cloned as this; } 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); } } } private __helper__: CoreDirectionalLightHelper | undefined; } export class CoreDirectionalLightHelper { public object: Mesh = new Mesh(); private _lineMaterial = new LineBasicMaterial(); private _cameraHelper!: CoreCameraHelper; private _square = new Line(); constructor(public container: DirectionalLightContainer) { 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.rotateX(Math.PI * 0.5); this._square.updateMatrix(); this._square.matrixAutoUpdate = false; this.object.add(this._square); this._cameraHelper = new CoreCameraHelper(light.shadow.camera); // this._cameraHelper.rotateX(-Math.PI * 0.5); 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); } }