@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
160 lines (144 loc) • 5.35 kB
text/typescript
import {BaseSopOperation} from './_Base';
import {BufferGeometry, Vector2, Vector3, PlaneGeometry, Quaternion, BoxGeometry, Box3} from 'three';
import {CoreTransform, rotateGeometry} from '../../../core/Transform';
import {CoreGroup} from '../../../core/geometry/Group';
import {InputCloneMode} from '../../../engine/poly/InputCloneMode';
import {isBooleanTrue} from '../../../core/BooleanValue';
import {DefaultOperationParams} from '../../../core/operations/_Base';
import {ObjectType} from '../../../core/geometry/Constant';
const tmpBox = new Box3();
const tmpBoxPreRotation = new Box3();
const tmpSize = new Vector3();
const tmpCenter = new Vector3();
const DEFAULT_UP = new Vector3(0, 0, 1);
const q = new Quaternion();
// const size = new Vector3();
// const center = new Vector3();
interface PlaneSopParams extends DefaultOperationParams {
size: Vector2;
useSegmentsCount: boolean;
stepSize: number;
segments: Vector2;
direction: Vector3;
center: Vector3;
asLines: boolean;
}
export const DEFAULT_PARAMS: PlaneSopParams = {
size: new Vector2(1, 1),
useSegmentsCount: false,
stepSize: 1,
segments: new Vector2(1, 1),
direction: new Vector3(0, 1, 0),
center: new Vector3(0, 0, 0),
asLines: false,
};
const _segmentsCount = new Vector2(1, 1);
export class PlaneSopOperation extends BaseSopOperation {
static override readonly DEFAULT_PARAMS = DEFAULT_PARAMS;
static override readonly INPUT_CLONED_STATE = InputCloneMode.NEVER;
static override type(): Readonly<'plane'> {
return 'plane';
}
private _coreTransform = new CoreTransform();
override cook(inputCoreGroups: CoreGroup[], params: PlaneSopParams) {
const coreGroup = inputCoreGroups[0];
if (coreGroup) {
return this._cookWithInput(coreGroup, params);
} else {
return this._cookWithoutInput(params);
}
}
private _cookWithoutInput(params: PlaneSopParams) {
const geometry = this._createPlane(params.size, params);
// convert to buffer geo, as some render problems can occur otherwise
// geometry = BufferGeometryUtils.mergeGeometries([geometry])
// console.log(geometry, geometry.isBufferGeometry)
rotateGeometry(geometry, DEFAULT_UP, params.direction);
const matrix = this._coreTransform.translationMatrix(params.center);
geometry.applyMatrix4(matrix);
const object = this._createPlaneObject(geometry, params);
return this.createCoreGroupFromObjects([object]);
}
private _cookWithInput(coreGroup: CoreGroup, params: PlaneSopParams) {
coreGroup.boundingBox(tmpBoxPreRotation);
tmpBoxPreRotation.getCenter(tmpCenter);
// create box
coreGroup.boundingBox(tmpBox);
tmpBox.getSize(tmpSize);
tmpBox.getCenter(tmpCenter);
const boxGeometry = new BoxGeometry(tmpSize.x, tmpSize.y, tmpSize.z, 1, 1, 1);
// rotate box
function _applyInputQuaternion(_q: Quaternion) {
boxGeometry.applyQuaternion(_q);
boxGeometry.computeBoundingBox();
}
function _setInputRotation() {
q.setFromUnitVectors(DEFAULT_UP, params.direction);
_applyInputQuaternion(q);
}
// function _resetInputRotation() {
// q.invert();
// _applyInputQuaternion(q);
// }
_setInputRotation();
const bboxPostRotation = boxGeometry.boundingBox!; //coreGroup.boundingBox(true);
bboxPostRotation.getSize(tmpSize);
// bboxPreRotation.getCenter(center); // debug
// _resetInputRotation();
const size2d = new Vector2(tmpSize.x, tmpSize.y);
const geometry = this._createPlane(size2d, params);
rotateGeometry(geometry, DEFAULT_UP, params.direction);
geometry.translate(tmpCenter.x, tmpCenter.y, tmpCenter.z);
const object = this._createPlaneObject(geometry, params);
return this.createCoreGroupFromObjects([object]);
}
private _createPlaneObject(geometry: BufferGeometry, params: PlaneSopParams) {
return BaseSopOperation.createObject(geometry, params.asLines ? ObjectType.LINE_SEGMENTS : ObjectType.MESH);
}
private _createPlane(size: Vector2, params: PlaneSopParams) {
size = size.clone();
if (isBooleanTrue(params.useSegmentsCount)) {
_segmentsCount.x = Math.floor(params.segments.x);
_segmentsCount.y = Math.floor(params.segments.y);
} else {
if (params.stepSize > 0) {
size.x = Math.max(size.x, params.stepSize);
size.y = Math.max(size.y, params.stepSize);
_segmentsCount.x = Math.floor(size.x / params.stepSize);
_segmentsCount.y = Math.floor(size.y / params.stepSize);
size.x = _segmentsCount.x * params.stepSize;
size.y = _segmentsCount.y * params.stepSize;
}
}
const geometry = new PlaneGeometry(size.x, size.y, _segmentsCount.x, _segmentsCount.y);
if (isBooleanTrue(params.asLines)) {
const gridX = Math.floor(_segmentsCount.x);
const gridY = Math.floor(_segmentsCount.y);
const gridX1 = gridX + 1;
// const gridY1 = gridY + 1;
const indices: number[] = [];
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = ix + gridX1 * iy;
const b = ix + gridX1 * (iy + 1);
const d = ix + 1 + gridX1 * iy;
indices.push(a, b);
indices.push(a, d);
const lastX = ix == gridX - 1;
const lastY = iy == gridY - 1;
if (lastX || lastY) {
const c = ix + 1 + gridX1 * (iy + 1);
if (lastX) {
indices.push(d, c);
}
if (lastY) {
indices.push(b, c);
}
}
}
}
geometry.setIndex(indices);
}
return geometry;
}
}