UNPKG

polygonjs-engine

Version:

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

133 lines (109 loc) 4.13 kB
/** * 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; } }