UNPKG

polygonjs-engine

Version:

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

113 lines (102 loc) 3.91 kB
/** * Allows easy position of lights, or any object around another one. * * @remarks * This node transforms its children with latitude and longitude controls, instead of typical translate and rotate. It makes it more intuitive to position objects such as lights. * */ import {TypedObjNode} from './_Base'; import {Group} from 'three/src/objects/Group'; import {FlagsControllerD} from '../utils/FlagsController'; import {AxesHelper} from 'three/src/helpers/AxesHelper'; import {HierarchyController} from './utils/HierarchyController'; import {Matrix4} from 'three/src/math/Matrix4'; import {Vector3} from 'three/src/math/Vector3'; import {MathUtils} from 'three/src/math/MathUtils'; import {Quaternion} from 'three/src/math/Quaternion'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; class PolarTransformObjParamConfig extends NodeParamsConfig { center = ParamConfig.VECTOR3([0, 0, 0]); longitude = ParamConfig.FLOAT(0, { range: [0, 360], }); latitude = ParamConfig.FLOAT(0, { range: [-180, 180], }); depth = ParamConfig.FLOAT(1, { range: [0, 10], }); } const ParamsConfig = new PolarTransformObjParamConfig(); const HOOK_NAME = '_cook_main_without_inputs_when_dirty'; const AXIS_VERTICAL = new Vector3(0, 1, 0); const AXIS_HORIZONTAL = new Vector3(-1, 0, 0); export class PolarTransformObjNode extends TypedObjNode<Group, PolarTransformObjParamConfig> { params_config = ParamsConfig; static type() { return 'polarTransform'; } readonly hierarchy_controller: HierarchyController = new HierarchyController(this); public readonly flags: FlagsControllerD = new FlagsControllerD(this); private _helper = new AxesHelper(1); create_object() { const group = new Group(); group.matrixAutoUpdate = false; return group; } initializeNode() { this.hierarchy_controller.initializeNode(); if (!this.dirtyController.has_hook(HOOK_NAME)) { this.dirtyController.addPostDirtyHook(HOOK_NAME, this._cook_main_without_inputs_when_dirty_bound); } this._updateHelperHierarchy(); this._helper.matrixAutoUpdate = false; this.flags.display.add_hook(() => { this._updateHelperHierarchy(); }); } private _updateHelperHierarchy() { if (this.flags.display.active()) { this.object.add(this._helper); } else { this.object.remove(this._helper); } } // TODO: this will have to be checked via the parent, when I will have obj managers at lower levels than root private _cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this); private async _cook_main_without_inputs_when_dirty() { await this.cookController.cook_main_without_inputs(); } private _centerMatrix = new Matrix4(); private _longitudeMatrix = new Matrix4(); private _latitudeMatrix = new Matrix4(); private _depthMatrix = new Matrix4(); private _fullMatrix = new Matrix4(); private _decomposed = { t: new Vector3(), q: new Quaternion(), s: new Vector3(), }; cook() { const object = this.object; this._centerMatrix.identity(); this._longitudeMatrix.identity(); this._latitudeMatrix.identity(); this._depthMatrix.identity(); this._centerMatrix.makeTranslation(this.pv.center.x, this.pv.center.y, this.pv.center.z); this._longitudeMatrix.makeRotationAxis(AXIS_VERTICAL, MathUtils.degToRad(this.pv.longitude)); this._latitudeMatrix.makeRotationAxis(AXIS_HORIZONTAL, MathUtils.degToRad(this.pv.latitude)); this._depthMatrix.makeTranslation(0, 0, this.pv.depth); this._fullMatrix .copy(this._centerMatrix) .multiply(this._longitudeMatrix) .multiply(this._latitudeMatrix) .multiply(this._depthMatrix); this._fullMatrix.decompose(this._decomposed.t, this._decomposed.q, this._decomposed.s); object.position.copy(this._decomposed.t); object.quaternion.copy(this._decomposed.q); object.scale.copy(this._decomposed.s); object.updateMatrix(); this.cookController.end_cook(); } }