@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
134 lines (133 loc) • 4.73 kB
JavaScript
;
import { BaseSopOperation } from "./_Base";
import {
BufferGeometry,
CatmullRomCurve3,
Float32BufferAttribute,
Vector3,
Vector2
} from "three";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { ObjectType } from "../../../core/geometry/Constant";
import { SPLINE_CURVE_TYPES } from "../../../core/geometry/Curve";
import { ObjectUserData } from "../../../core/UserData";
import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils";
import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory";
const tmpV2 = new Vector2();
const current = new Vector3();
const next = new Vector3();
const _points = [];
export class CurveFromPointsSopOperation extends BaseSopOperation {
static type() {
return "curveFromPoint";
}
cook(inputCoreGroups, params) {
const inputCoreGroup = inputCoreGroups[0];
const objects = inputCoreGroup.allObjects();
const newObjects = [];
for (let object of objects) {
const newObject = this._createCurveFromCoreObject(object, params);
if (newObject) {
newObjects.push(newObject);
}
}
return this.createCoreGroupFromObjects(newObjects);
}
_createCurveFromCoreObject(object, params) {
const { pointsCount, closed, curveType, tension, tTangent } = params;
const corePointClass = corePointClassFactory(object);
pointsFromObject(object, _points);
const pointPositions = _points.map((p) => p.position(new Vector3()));
if (pointPositions.length < 2) {
return;
}
const curveTypeName = SPLINE_CURVE_TYPES[curveType];
const curve = new CatmullRomCurve3(pointPositions, closed, curveTypeName, tension);
const indices = new Array(pointsCount);
for (let i = 0; i < pointsCount; i++) {
if (i > 0) {
indices[(i - 1) * 2] = i - 1;
indices[(i - 1) * 2 + 1] = i;
}
}
const geometry = new BufferGeometry();
geometry.setIndex(indices);
const attribNamesToInterpolate = ["position"];
for (const attribName of attribNamesToInterpolate) {
const attribSize = corePointClass.attribSize(object, attribName);
let attribPositions = [];
switch (attribSize) {
case 1: {
attribPositions = _points.map((p) => new Vector3(p.attribValue(attribName), 0, 0));
break;
}
case 2: {
attribPositions = _points.map((p) => {
p.attribValue(attribName, tmpV2);
return new Vector3(tmpV2.x, tmpV2.y, 0);
});
break;
}
case 3: {
attribPositions = _points.map((p) => {
p.attribValue(attribName, current);
return current.clone();
});
break;
}
}
const curveTypeName2 = SPLINE_CURVE_TYPES[curveType];
const curve2 = new CatmullRomCurve3(attribPositions, closed, curveTypeName2, tension);
const attribValues = new Array(pointsCount * attribSize);
for (let i = 0; i < pointsCount; i++) {
const t = i / (pointsCount - 1);
curve2.getPoint(t, current);
switch (attribSize) {
case 1: {
attribValues[i] = current.x;
break;
}
case 2: {
attribValues[2 * i] = current.x;
attribValues[2 * i + 1] = current.y;
break;
}
case 3: {
current.toArray(attribValues, i * 3);
break;
}
}
}
geometry.setAttribute(attribName, new Float32BufferAttribute(attribValues, attribSize));
}
if (tTangent) {
const positions = geometry.getAttribute("position").array;
const tangentName = params.tangentName;
const tangents = new Array(pointsCount * 3);
for (let i = 0; i < pointsCount - 1; i++) {
current.fromArray(positions, i * 3);
next.fromArray(positions, (i + 1) * 3);
next.sub(current).normalize();
next.toArray(tangents, i * 3);
}
current.fromArray(positions, (pointsCount - 1) * 3);
next.fromArray(positions, (pointsCount - 2) * 3);
current.sub(next).normalize();
next.toArray(tangents, (pointsCount - 1) * 3);
geometry.setAttribute(tangentName, new Float32BufferAttribute(tangents, 3));
}
const newObject = BaseSopOperation.createObject(geometry, ObjectType.LINE_SEGMENTS);
newObject.userData[ObjectUserData.PATH] = curve;
return newObject;
}
}
CurveFromPointsSopOperation.DEFAULT_PARAMS = {
pointsCount: 100,
closed: false,
curveType: 0,
tension: 0.5,
tTangent: false,
tangentName: "tangent"
// attributesToInterpolate: '',
};
CurveFromPointsSopOperation.INPUT_CLONED_STATE = InputCloneMode.NEVER;