@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
171 lines (170 loc) • 6.39 kB
JavaScript
"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();
}
}