UNPKG

@polygonjs/polygonjs

Version:

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

171 lines (170 loc) 6.39 kB
"use strict"; import { TypedObjNode } from "../_Base"; import { Matrix4 } from "three"; import { CoreTransform, ROTATION_ORDERS, RotationOrder } from "../../../../core/Transform"; import { NodeParamsConfig, ParamConfig } from "../../utils/params/ParamsConfig"; import { isBooleanTrue } from "../../../../core/BooleanValue"; import { Poly } from "../../../Poly"; export function TransformedParamConfig(Base, default_params) { const matrixAutoUpdate = (default_params == null ? void 0 : default_params.matrixAutoUpdate) || false; return class Mixin extends Base { constructor() { super(...arguments); this.transform = ParamConfig.FOLDER(); /** @param toggle on to keep world position when adding a parent or removing from one */ this.keepPosWhenParenting = ParamConfig.BOOLEAN(0); /** @param rotation order */ this.rotationOrder = ParamConfig.INTEGER(ROTATION_ORDERS.indexOf(RotationOrder.XYZ), { menu: { entries: ROTATION_ORDERS.map((order, v) => { return { name: order, value: v }; }) } }); /** @param translate */ this.t = ParamConfig.VECTOR3([0, 0, 0]); /** @param rotation */ this.r = ParamConfig.VECTOR3([0, 0, 0]); /** @param scale */ this.s = ParamConfig.VECTOR3([1, 1, 1]); /** @param scale */ this.scale = ParamConfig.FLOAT(1); // pivot = ParamConfig.VECTOR3([0, 0, 0]); /** @param set for the matrix to be updated every frame */ this.matrixAutoUpdate = ParamConfig.BOOLEAN(matrixAutoUpdate ? 1 : 0); this.updateTransformFromObject = ParamConfig.BUTTON(null, { callback: (node) => { TransformController.PARAM_CALLBACK_update_transform_from_object(node); } }); } // tlookAt = ParamConfig.BOOLEAN(0); // lookAtPos = ParamConfig.VECTOR3([0, 0, 0], { // visibleIf: {tlookAt: 1}, // }); // look_at = ParamConfig.OPERATOR_PATH('', { // visibleIf: {tlookAt: 1}, // nodeSelection: {context: NodeContext.OBJ}, // }); // up = ParamConfig.VECTOR3([0, 1, 0], { // visibleIf: {tlookAt: 1}, // }); }; } class TransformedParamsConfig extends TransformedParamConfig(NodeParamsConfig) { } export class TransformedObjNode extends TypedObjNode { constructor() { super(...arguments); this.transformController = new TransformController(this); } } const HOOK_NAME = "_cook_main_without_inputs_when_dirty"; export class TransformController { constructor(node) { this.node = node; // TODO: this will have to be checked via the parent, when I will have obj managers at lower levels than root this._cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this); this._core_transform = new CoreTransform(); // private _keep_pos_when_parenting_t = new Vector3(); // private _keep_pos_when_parenting_q = new Quaternion(); // private _keep_pos_when_parenting_s = new Vector3(); this._keep_pos_when_parenting_m_object = new Matrix4(); this._keep_pos_when_parenting_m_new_parent_inv = new Matrix4(); } initializeNode() { if (!this.node.dirtyController.hasHook(HOOK_NAME)) { this.node.dirtyController.addPostDirtyHook(HOOK_NAME, this._cook_main_without_inputs_when_dirty_bound); } } async _cook_main_without_inputs_when_dirty() { await this.node.cookController.cookMainWithoutInputs(); } update() { this.update_transform_with_matrix(); const object = this.node.object; object.matrixAutoUpdate = isBooleanTrue(this.node.pv.matrixAutoUpdate); Poly.onSceneUpdatedHooks.runHooks(); } update_transform_with_matrix(matrix) { const object = this.node.object; if (matrix != null && !matrix.equals(object.matrix)) { object.matrix.copy(matrix); object.dispatchEvent({ type: "change" }); } else { this._update_matrix_from_params_with_core_transform(); } } _update_matrix_from_params_with_core_transform() { const object = this.node.object; let prev_auto_update = object.matrixAutoUpdate; if (prev_auto_update) { object.matrixAutoUpdate = false; } const matrix = this._core_transform.matrix( this.node.pv.t, this.node.pv.r, this.node.pv.s, this.node.pv.scale, ROTATION_ORDERS[this.node.pv.rotationOrder] ); object.matrix.identity(); object.applyMatrix4(matrix); this._apply_look_at(); object.updateMatrix(); if (prev_auto_update) { object.matrixAutoUpdate = true; } object.dispatchEvent({ type: "change" }); } // private _look_at_target_t = new Vector3(); // private _look_at_target_q = new Quaternion(); // private _look_at_target_s = new Vector3(); _apply_look_at() { } set_params_from_matrix(matrix, options = {}) { CoreTransform.setParamsFromMatrix(matrix, this.node, options); } // // // KEEP POS WHEN PARENTING // // static update_node_transform_params_if_required(node, new_parent_object) { node.transformController.update_node_transform_params_if_required(new_parent_object); } update_node_transform_params_if_required(new_parent_object) { if (!isBooleanTrue(this.node.pv.keepPosWhenParenting)) { return; } if (!this.node.scene().loadingController.loaded()) { return; } if (new_parent_object == this.node.object.parent) { return; } const object = this.node.object; object.updateMatrixWorld(true); new_parent_object.updateMatrixWorld(true); this._keep_pos_when_parenting_m_object.copy(object.matrixWorld); this._keep_pos_when_parenting_m_new_parent_inv.copy(new_parent_object.matrixWorld); this._keep_pos_when_parenting_m_new_parent_inv.invert(); this._keep_pos_when_parenting_m_object.premultiply(this._keep_pos_when_parenting_m_new_parent_inv); CoreTransform.setParamsFromMatrix(this._keep_pos_when_parenting_m_object, this.node, { scale: true }); } update_node_transform_params_from_object(update_matrix = false) { const object = this.node.object; if (update_matrix) { object.updateMatrix(); } CoreTransform.setParamsFromMatrix(object.matrix, this.node, { scale: true }); } // // // CALLBACK // // static PARAM_CALLBACK_update_transform_from_object(node) { node.transformController.update_node_transform_params_from_object(); } }