UNPKG

@polygonjs/polygonjs

Version:

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

190 lines (176 loc) 6.38 kB
import {BaseSopOperation} from './_Base'; import {CoreGroup, Object3DWithGeometry} from '../../../core/geometry/Group'; import {TypeAssert} from '../../../engine/poly/Assert'; import { CoreTransform, ROTATION_ORDERS, RotationOrder, TransformTargetType, TRANSFORM_TARGET_TYPES, } from '../../../core/Transform'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {coreObjectClassFactory} from '../../../core/geometry/CoreObjectFactory'; import {MathUtils, Vector3, Object3D, Matrix4, Euler, Quaternion} from 'three'; import {DefaultOperationParams} from '../../../core/operations/_Base'; import { OBJECT_TRANSFORM_SPACES, OBJECT_TRANSFORM_MODES, ObjectTransformMode, ObjectTransformSpace, applyTransformWithSpaceToObject, } from '../../../core/TransformSpace'; import {CoreObjectType, isObject3D, ObjectContent} from '../../../core/geometry/ObjectContent'; import {CoreMask} from '../../../core/geometry/Mask'; import {SopType} from '../../poly/registers/nodes/types/Sop'; import {pointsFromObjectFromGroup} from '../../../core/geometry/entities/point/CorePointUtils'; import {CorePoint} from '../../../core/geometry/entities/point/CorePoint'; // const _t = new Vector3(); const _r = new Vector3(); const _euler = new Euler(); const _q = new Quaternion(); const _s = new Vector3(); const _mat4 = new Matrix4(); const _pointPos = new Vector3(); interface TransformSopParams extends DefaultOperationParams { applyOn: number; group: string; // objectMode: number; objectTransformSpace: number; pointGroup: string; rotationOrder: number; t: Vector3; r: Vector3; s: Vector3; scale: number; pivot: Vector3; } const _points: CorePoint<CoreObjectType>[] = []; export class TransformSopOperation extends BaseSopOperation { static override readonly DEFAULT_PARAMS: TransformSopParams = { applyOn: TRANSFORM_TARGET_TYPES.indexOf(TransformTargetType.GEOMETRY), group: '', objectMode: OBJECT_TRANSFORM_MODES.indexOf(ObjectTransformMode.SET), objectTransformSpace: OBJECT_TRANSFORM_SPACES.indexOf(ObjectTransformSpace.PARENT), pointGroup: '', rotationOrder: ROTATION_ORDERS.indexOf(RotationOrder.XYZ), t: new Vector3(0, 0, 0), r: new Vector3(0, 0, 0), s: new Vector3(1, 1, 1), scale: 1, pivot: new Vector3(0, 0, 0), }; static override readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; static override type(): Readonly<SopType.TRANSFORM> { return SopType.TRANSFORM; } private _coreTransform = new CoreTransform(); override cook(inputCoreGroups: CoreGroup[], params: TransformSopParams) { const coreGroup = inputCoreGroups[0]; const selectedObjects = CoreMask.filterObjects(coreGroup, params); for (const inputObject of selectedObjects) { this._applyTransform(inputObject, coreGroup, params); } coreGroup.resetBoundingBox(); return coreGroup; } private _applyTransform(object: ObjectContent<CoreObjectType>, coreGroup: CoreGroup, params: TransformSopParams) { if (isObject3D(object)) { this._applyTransformWithTransformTargetType(object, coreGroup, params); } else { this._applyTransformWithoutTransformTargetType(object, params); } } private _applyTransformWithoutTransformTargetType( object: ObjectContent<CoreObjectType>, params: TransformSopParams ) { this._updateObject(object, params); } private _applyTransformWithTransformTargetType(object: Object3D, coreGroup: CoreGroup, params: TransformSopParams) { const mode = TRANSFORM_TARGET_TYPES[params.applyOn]; switch (mode) { case TransformTargetType.GEOMETRY: { return this._updateGeometry(object, params); } case TransformTargetType.OBJECT: { return this._updateObject(object, params); } } TypeAssert.unreachable(mode); } private _updateGeometry(object: Object3D, params: TransformSopParams) { const matrix = this._matrix(params); const pointGroup = params.pointGroup; if (pointGroup.trim() === '') { const geometry = (object as Object3DWithGeometry).geometry; if (geometry) { geometry.translate(-params.pivot.x, -params.pivot.y, -params.pivot.z); geometry.applyMatrix4(matrix); geometry.translate(params.pivot.x, params.pivot.y, params.pivot.z); } } else { pointsFromObjectFromGroup(object, pointGroup, _points); for (const point of _points) { const position = point.position(_pointPos).sub(params.pivot); position.applyMatrix4(matrix); point.setPosition(position.add(params.pivot)); } } } private _updateObject(object: ObjectContent<CoreObjectType>, params: TransformSopParams) { const objectMode = OBJECT_TRANSFORM_MODES[params.objectMode]; switch (objectMode) { case ObjectTransformMode.SET: { return this._setMatrix(object, params); } case ObjectTransformMode.MULT: { return this._multMatrix(object, params); } } TypeAssert.unreachable(objectMode); } private _setMatrix(object: ObjectContent<CoreObjectType>, params: TransformSopParams) { const order = ROTATION_ORDERS[params.rotationOrder]; _r.copy(params.r).multiplyScalar(MathUtils.DEG2RAD); _euler.set(_r.x, _r.y, _r.z, order); _q.setFromEuler(_euler); _s.copy(params.s).multiplyScalar(params.scale); _mat4.compose(params.t, _q, _s); coreObjectClassFactory(object).applyMatrix( object, _mat4, TRANSFORM_TARGET_TYPES[params.applyOn], ObjectTransformSpace.LOCAL, ObjectTransformMode.SET ); } // private _objectPosition = new Vector3(); private _multMatrix(object: ObjectContent<CoreObjectType>, params: TransformSopParams) { const matrix = this._matrix(params); const transformSpace = OBJECT_TRANSFORM_SPACES[params.objectTransformSpace]; // for (let object of objects) { applyTransformWithSpaceToObject(object, matrix, transformSpace, ObjectTransformMode.MULT); // // center to origin // // this._objectPosition.copy(object.position); // // object.position.set(0, 0, 0); // object.updateMatrix(); // // apply matrix // // object.applyMatrix4(matrix); // object.matrix.multiply(matrix); // // revert to position // // object.position.add(this._objectPosition); // // object.updateMatrix(); // object.matrix.decompose(object.position, object.quaternion, object.scale); // } } private _matrix(params: TransformSopParams) { return this._coreTransform.matrix( params.t, params.r, params.s, params.scale, ROTATION_ORDERS[params.rotationOrder] ); } }