@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
174 lines (173 loc) • 5.91 kB
JavaScript
"use strict";
import { TypedObjNode } from "./_Base";
import { Mesh } from "three";
import { FlagsControllerD } from "../utils/FlagsController";
import { AxesHelper } from "three";
import { HierarchyController } from "./utils/HierarchyController";
import { NodeContext } from "../../poly/NodeContext";
import { Vector3 } from "three";
import { Quaternion } from "three";
var BlendMode = /* @__PURE__ */ ((BlendMode2) => {
BlendMode2["TOGETHER"] = "translate + rotate together";
BlendMode2["SEPARATELY"] = "translate + rotate separately";
return BlendMode2;
})(BlendMode || {});
const BLEND_MODES = ["translate + rotate together" /* TOGETHER */, "translate + rotate separately" /* SEPARATELY */];
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { TypeAssert } from "../../poly/Assert";
import { isBooleanTrue } from "../../../core/Type";
class BlendObjParamConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param object to blend transform from */
this.object0 = ParamConfig.NODE_PATH("", {
nodeSelection: {
context: NodeContext.OBJ
}
});
/** @param object to blend transform to */
this.object1 = ParamConfig.NODE_PATH("", {
nodeSelection: {
context: NodeContext.OBJ
}
});
/** @param blend mode */
this.mode = ParamConfig.INTEGER(BLEND_MODES.indexOf("translate + rotate together" /* TOGETHER */), {
menu: {
entries: BLEND_MODES.map((name, value) => {
return { name, value };
})
}
});
/** @param blend value */
this.blend = ParamConfig.FLOAT(0, {
visibleIf: { mode: BLEND_MODES.indexOf("translate + rotate together" /* TOGETHER */) },
range: [0, 1],
rangeLocked: [false, false]
});
/** @param blend translation value */
this.blendT = ParamConfig.FLOAT(0, {
visibleIf: { mode: BLEND_MODES.indexOf("translate + rotate separately" /* SEPARATELY */) },
range: [0, 1],
rangeLocked: [false, false]
});
/** @param blend rotation value */
this.blendR = ParamConfig.FLOAT(0, {
visibleIf: { mode: BLEND_MODES.indexOf("translate + rotate separately" /* SEPARATELY */) },
range: [0, 1],
rangeLocked: [false, false]
});
/** @param updateOnRender */
this.updateOnRender = ParamConfig.BOOLEAN(1);
}
}
const ParamsConfig = new BlendObjParamConfig();
export class BlendObjNode extends TypedObjNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
this.hierarchyController = new HierarchyController(this);
this.flags = new FlagsControllerD(this);
this._helper = new AxesHelper(1);
this._t0 = new Vector3();
this._q0 = new Quaternion();
this._s0 = new Vector3();
this._t1 = new Vector3();
this._q1 = new Quaternion();
this._s1 = new Vector3();
}
static type() {
return "blend";
}
createObject() {
const object = new Mesh();
object.matrixAutoUpdate = false;
object.onBeforeRender = this._onBeforeRender.bind(this);
return object;
}
initializeNode() {
this.hierarchyController.initializeNode();
this.io.inputs.setCount(0);
this.addPostDirtyHook("blendOnDirty", () => {
this.cookController.cookMainWithoutInputs();
});
this._updateHelperHierarchy();
this.flags.display.onUpdate(() => {
this._updateHelperHierarchy();
});
}
_updateHelperHierarchy() {
if (this.flags.display.active()) {
this.object.add(this._helper);
} else {
this.object.remove(this._helper);
}
}
async cook() {
this.object.frustumCulled = !this.pv.updateOnRender;
const objNode0 = this.pv.object0.nodeWithContext(NodeContext.OBJ, this.states.error);
const objNode1 = this.pv.object1.nodeWithContext(NodeContext.OBJ, this.states.error);
if (objNode0 && objNode1) {
if (objNode0.isDirty()) {
await objNode0.compute();
}
if (objNode1.isDirty()) {
await objNode1.compute();
}
this._object0 = objNode0.object;
this._object1 = objNode1.object;
this._computeBlendedMatrix();
} else {
this.states.error.set("blend targets not found");
}
this.cookController.endCook();
}
_onBeforeRender() {
if (!isBooleanTrue(this.pv.updateOnRender)) {
return;
}
this._computeBlendedMatrix();
}
_computeBlendedMatrix() {
if (!(this._object0 && this._object1)) {
return;
}
const mode = BLEND_MODES[this.pv.mode];
switch (mode) {
case "translate + rotate together" /* TOGETHER */:
return this._blendTogether(this._object0, this._object1);
case "translate + rotate separately" /* SEPARATELY */:
return this._blendSeparately(this._object0, this._object1);
}
TypeAssert.unreachable(mode);
}
_blendTogether(object0, object1) {
this._decomposeMatrices(object0, object1);
this._object.position.copy(this._t0).lerp(this._t1, this.pv.blend);
this._object.quaternion.copy(this._q0).slerp(this._q1, this.pv.blend);
if (!this._object.matrixAutoUpdate) {
this._object.updateMatrix();
}
}
_blendSeparately(object0, object1) {
this._decomposeMatrices(object0, object1);
this._object.position.copy(this._t0).lerp(this._t1, this.pv.blendT);
this._object.quaternion.copy(this._q0).slerp(this._q1, this.pv.blendR);
if (!this._object.matrixAutoUpdate) {
this._object.updateMatrix();
}
}
_decomposeMatrices(object0, object1) {
this._updateMatrix(object0);
this._updateMatrix(object1);
object0.matrixWorld.decompose(this._t0, this._q0, this._s0);
object1.matrixWorld.decompose(this._t1, this._q1, this._s1);
}
_updateMatrix(object) {
if (!object.matrixAutoUpdate) {
object.updateMatrix();
object.updateMatrixWorld(true);
object.updateWorldMatrix(true, true);
}
}
}