polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
110 lines (102 loc) • 3.41 kB
text/typescript
import {BaseSopOperation} from './_Base';
import {CoreGroup, Object3DWithGeometry} from '../../geometry/Group';
import {Vector3} from 'three/src/math/Vector3';
import {Matrix4} from 'three/src/math/Matrix4';
import {Object3D} from 'three/src/core/Object3D';
import {TypeAssert} from '../../../engine/poly/Assert';
import {DefaultOperationParams} from '../_Base';
import {
CoreTransform,
ROTATION_ORDERS,
RotationOrder,
TransformTargetType,
TRANSFORM_TARGET_TYPES,
} from '../../../core/Transform';
import {InputCloneMode} from '../../../engine/poly/InputCloneMode';
interface TransformSopParams extends DefaultOperationParams {
applyOn: number;
group: string;
rotationOrder: number;
t: Vector3;
r: Vector3;
s: Vector3;
scale: number;
pivot: Vector3;
}
export class TransformSopOperation extends BaseSopOperation {
static readonly DEFAULT_PARAMS: TransformSopParams = {
applyOn: TRANSFORM_TARGET_TYPES.indexOf(TransformTargetType.GEOMETRIES),
group: '',
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 readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE;
static type(): Readonly<'transform'> {
return 'transform';
}
private _core_transform = new CoreTransform();
cook(input_contents: CoreGroup[], params: TransformSopParams) {
const objects = input_contents[0].objectsWithGeo();
const matrix = this._core_transform.matrix(
params.t,
params.r,
params.s,
params.scale,
ROTATION_ORDERS[params.rotationOrder]
);
this._apply_transform(objects, params, matrix);
return input_contents[0];
}
private _apply_transform(objects: Object3DWithGeometry[], params: TransformSopParams, matrix: Matrix4) {
const mode = TRANSFORM_TARGET_TYPES[params.applyOn];
switch (mode) {
case TransformTargetType.GEOMETRIES: {
return this._apply_matrix_to_geometries(objects, params, matrix);
}
case TransformTargetType.OBJECTS: {
return this._apply_matrix_to_objects(objects, params, matrix);
}
}
TypeAssert.unreachable(mode);
}
private _apply_matrix_to_geometries(objects: Object3DWithGeometry[], params: TransformSopParams, matrix: Matrix4) {
if (params.group === '') {
for (let object of objects) {
let geometry;
if ((geometry = object.geometry) != null) {
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 {
object.applyMatrix4(matrix);
}
}
} else {
const core_group = CoreGroup._fromObjects(objects);
const points = core_group.pointsFromGroup(params.group);
for (let point of points) {
const position = point.position().sub(params.pivot);
position.applyMatrix4(matrix);
point.setPosition(position.add(params.pivot));
}
}
}
private _object_position = new Vector3();
private _apply_matrix_to_objects(objects: Object3D[], params: TransformSopParams, matrix: Matrix4) {
for (let object of objects) {
// center to origin
this._object_position.copy(object.position);
object.position.multiplyScalar(0);
object.updateMatrix();
// apply matrix
object.applyMatrix4(matrix);
// revert to positoin
object.position.add(this._object_position);
object.updateMatrix();
}
}
}