polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
138 lines (137 loc) • 5.3 kB
JavaScript
import {TypedObjNode} from "../_Base";
import {Matrix4 as Matrix42} from "three/src/math/Matrix4";
import {CoreTransform, ROTATION_ORDERS, RotationOrder} from "../../../../core/Transform";
import {NodeParamsConfig, ParamConfig} from "../../utils/params/ParamsConfig";
export function TransformedParamConfig(Base3, default_params) {
const matrixAutoUpdate = default_params?.matrixAutoUpdate || false;
return class Mixin extends Base3 {
constructor() {
super(...arguments);
this.transform = ParamConfig.FOLDER();
this.keepPosWhenParenting = ParamConfig.BOOLEAN(0);
this.rotationOrder = ParamConfig.INTEGER(ROTATION_ORDERS.indexOf(RotationOrder.XYZ), {
menu: {
entries: ROTATION_ORDERS.map((order, v) => {
return {name: order, value: v};
})
}
});
this.t = ParamConfig.VECTOR3([0, 0, 0]);
this.r = ParamConfig.VECTOR3([0, 0, 0]);
this.s = ParamConfig.VECTOR3([1, 1, 1]);
this.scale = ParamConfig.FLOAT(1);
this.matrixAutoUpdate = ParamConfig.BOOLEAN(matrixAutoUpdate ? 1 : 0);
this.updateTransformFromObject = ParamConfig.BUTTON(null, {
callback: (node) => {
TransformController.PARAM_CALLBACK_update_transform_from_object(node);
}
});
this.tlookAt = ParamConfig.BOOLEAN(0);
this.lookAtPos = ParamConfig.VECTOR3([0, 0, 0], {
visibleIf: {tlookAt: 1}
});
this.up = ParamConfig.VECTOR3([0, 1, 0], {
visibleIf: {tlookAt: 1}
});
}
};
}
class TransformedParamsConfig extends TransformedParamConfig(NodeParamsConfig) {
}
export class TransformedObjNode extends TypedObjNode {
constructor() {
super(...arguments);
this.transform_controller = new TransformController(this);
}
}
const HOOK_NAME = "_cook_main_without_inputs_when_dirty";
export class TransformController {
constructor(node) {
this.node = node;
this._cook_main_without_inputs_when_dirty_bound = this._cook_main_without_inputs_when_dirty.bind(this);
this._core_transform = new CoreTransform();
this._keep_pos_when_parenting_m_object = new Matrix42();
this._keep_pos_when_parenting_m_new_parent_inv = new Matrix42();
}
initializeNode() {
if (!this.node.dirtyController.has_hook(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.cook_main_without_inputs();
}
update() {
this.update_transform_with_matrix();
const object = this.node.object;
object.matrixAutoUpdate = this.node.pv.matrixAutoUpdate;
}
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"});
}
_apply_look_at() {
const pv = this.node.pv;
if (!pv.tlookAt) {
return;
}
this.node.object.up.copy(pv.up);
this.node.object.lookAt(pv.lookAtPos);
}
set_params_from_matrix(matrix, options = {}) {
CoreTransform.set_params_from_matrix(matrix, this.node, options);
}
static update_node_transform_params_if_required(node, new_parent_object) {
node.transform_controller.update_node_transform_params_if_required(new_parent_object);
}
update_node_transform_params_if_required(new_parent_object) {
if (!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.set_params_from_matrix(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.set_params_from_matrix(object.matrix, this.node, {scale: true});
}
static PARAM_CALLBACK_update_transform_from_object(node) {
node.transform_controller.update_node_transform_params_from_object();
}
}