polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
133 lines (109 loc) • 4.13 kB
text/typescript
/**
* Creates a tube-like geometry around a line.
*
*
*/
import {TypedSopNode} from './_Base';
import {CoreGeometry} from '../../../core/geometry/Geometry';
import {CoreTransform, DEFAULT_ROTATION_ORDER} from '../../../core/Transform';
import {CoreGeometryUtilCircle} from '../../../core/geometry/util/Circle';
import {CoreGeometryUtilCurve} from '../../../core/geometry/util/Curve';
import {CoreGeometryOperationSkin} from '../../../core/geometry/operation/Skin';
import {Vector3} from 'three/src/math/Vector3';
import {LineSegments} from 'three/src/objects/LineSegments';
import {BufferGeometry} from 'three/src/core/BufferGeometry';
import {InputCloneMode} from '../../poly/InputCloneMode';
const POSITION_ATTRIBUTE_NAME = 'position';
const DEFAULT_R = new Vector3(0, 0, 0);
const DEFAULT_S = new Vector3(1, 1, 1);
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {CoreGroup} from '../../../core/geometry/Group';
import {CorePoint} from '../../../core/geometry/Point';
import {ObjectType} from '../../../core/geometry/Constant';
class PolywireSopParamsConfig extends NodeParamsConfig {
/** @param radius */
radius = ParamConfig.FLOAT(1);
/** @param segments count on the circle used */
segmentsRadial = ParamConfig.INTEGER(8, {
range: [3, 20],
rangeLocked: [true, false],
});
/** @param toggle on for the geometry to close back on itself */
closed = ParamConfig.BOOLEAN(0);
}
const ParamsConfig = new PolywireSopParamsConfig();
export class PolywireSopNode extends TypedSopNode<PolywireSopParamsConfig> {
params_config = ParamsConfig;
static type() {
return 'polywire';
}
static displayedInputNames(): string[] {
return ['lines to create tubes from'];
}
private _core_transform = new CoreTransform();
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.NEVER);
}
private _geometries: BufferGeometry[] = [];
cook(input_contents: CoreGroup[]) {
const core_group = input_contents[0];
this._geometries = [];
for (let object of core_group.objects()) {
if (object instanceof LineSegments) {
this._create_tube(object);
}
}
const merged_geometry = CoreGeometry.merge_geometries(this._geometries);
for (let geometry of this._geometries) {
geometry.dispose();
}
if (merged_geometry) {
const object = this.create_object(merged_geometry, ObjectType.MESH);
this.setObject(object);
} else {
this.setObjects([]);
}
}
_create_tube(line_segment: LineSegments) {
const geometry = line_segment.geometry as BufferGeometry;
const wrapper = new CoreGeometry(geometry);
const points = wrapper.points();
const indices = geometry.getIndex()?.array as number[];
const accumulated_curve_point_indices = CoreGeometryUtilCurve.accumulated_curve_point_indices(indices);
for (let curve_point_indices of accumulated_curve_point_indices) {
const current_points = curve_point_indices.map((index) => points[index]);
this._create_tube_from_points(current_points);
}
}
_create_tube_from_points(points: CorePoint[]) {
if (points.length <= 1) {
return;
}
const positions = points.map((point) => point.attribValue(POSITION_ATTRIBUTE_NAME)) as Vector3[];
const circle_template = CoreGeometryUtilCircle.create(this.pv.radius, this.pv.segmentsRadial);
const circles: BufferGeometry[] = [];
const scale = 1;
for (let position of positions) {
const t = position;
const matrix = this._core_transform.matrix(t, DEFAULT_R, DEFAULT_S, scale, DEFAULT_ROTATION_ORDER);
const new_circle = circle_template.clone();
new_circle.applyMatrix4(matrix);
circles.push(new_circle);
}
for (let i = 0; i < circles.length; i++) {
if (i > 0) {
const circle = circles[i];
const prev_circle = circles[i - 1];
const geometry = this._skin(prev_circle, circle);
this._geometries.push(geometry);
}
}
}
_skin(geometry1: BufferGeometry, geometry0: BufferGeometry) {
const geometry = new BufferGeometry();
const operation = new CoreGeometryOperationSkin(geometry, geometry1, geometry0);
operation.process();
return geometry;
}
}