UNPKG

polygonjs-engine

Version:

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

190 lines (169 loc) 6.04 kB
/** * Processes the faces of the input geometry * * */ import {Vector3} from 'three/src/math/Vector3'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {BufferAttribute} from 'three/src/core/BufferAttribute'; import {Mesh} from 'three/src/objects/Mesh'; import {TypedSopNode} from './_Base'; import {CoreGroup} from '../../../core/geometry/Group'; import {InputCloneMode} from '../../poly/InputCloneMode'; import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig'; import {CorePoint} from '../../../core/geometry/Point'; import {CoreFace} from '../../../core/geometry/Face'; import {ArrayUtils} from '../../../core/ArrayUtils'; class FaceSopParamsConfig extends NodeParamsConfig { /** @param makes faces unique */ makeFacesUnique = ParamConfig.BOOLEAN(0); /** @param adds a vector3 attribute that represents the center of a face */ addFaceCenterAttribute = ParamConfig.BOOLEAN(0, { visibleIf: {makeFacesUnique: 1}, }); /** @param add an id attribute for each face */ addFaceId = ParamConfig.BOOLEAN(0, { visibleIf: {makeFacesUnique: 1}, }); /** @param allows to transform each face */ transform = ParamConfig.BOOLEAN(0, { visibleIf: {makeFacesUnique: 1}, }); /** @param scales the faces indepedently */ scale = ParamConfig.FLOAT(1, { visibleIf: {makeFacesUnique: 1, transform: 1}, }); } const ParamsConfig = new FaceSopParamsConfig(); export class FaceSopNode extends TypedSopNode<FaceSopParamsConfig> { params_config = ParamsConfig; static type() { return 'face'; } initializeNode() { this.io.inputs.setCount(1); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } cook(input_contents: CoreGroup[]) { const core_group = input_contents[0]; if (this.pv.makeFacesUnique) { this._makeFacesUnique(core_group); // we can only add face_center attrib // if the faces have been split // otherwise a point may belong to multiple faces if (this.pv.addFaceCenterAttribute) { this._addFaceCenterAttribute(core_group); } if (this.pv.addFaceId) { this._addFaceId(core_group); } if (this.pv.transform) { this._transform_faces(core_group); } } this.setCoreGroup(core_group); } private _makeFacesUnique(core_group: CoreGroup) { for (let object of core_group.objects()) { if ((object as Mesh).isMesh) { const geometry = (object as Mesh).geometry as BufferGeometry; const faces = ArrayUtils.chunk((geometry.index?.array as number[]) || [], 3); const points_count = faces.length * 3; for (let attrib_name of Object.keys(geometry.attributes)) { const attrib = geometry.attributes[attrib_name]; const attrib_size = attrib.itemSize; const new_values = new Float32Array(points_count * attrib_size); let new_value_index = 0; faces.forEach((face) => { face.forEach((index) => { for (let i = 0; i < attrib_size; i++) { const current_value = attrib.array[index * attrib_size + i]; new_values[new_value_index] = current_value; new_value_index += 1; } }); }); geometry.setAttribute(attrib_name, new BufferAttribute(new_values, attrib_size)); } const new_indices = ArrayUtils.range(points_count); geometry.setIndex(new_indices); } } } private _addFaceCenterAttribute(core_group: CoreGroup) { const attrib_name = 'face_center'; const face_center = new Vector3(); let faces: CoreFace[], face: CoreFace, points: CorePoint[], point: CorePoint; core_group.coreObjects().forEach((core_object) => { const object = core_object.object(); const core_geometry = core_object.coreGeometry(); if ((object as Mesh).isMesh && core_geometry) { faces = core_geometry.faces(); if (!core_geometry.hasAttrib(attrib_name)) { core_geometry.addNumericAttrib(attrib_name, 3, -1); } for (let fi = 0; fi < faces.length; fi++) { face = faces[fi]; face.center(face_center); points = face.points(); for (let pi = 0; pi < points.length; pi++) { point = points[pi]; point.setAttribValue(attrib_name, face_center); } } } }); } private _addFaceId(core_group: CoreGroup) { const attrib_name = 'face_id'; core_group.coreObjects().forEach((core_object) => { const object = core_object.object(); const core_geometry = core_object.coreGeometry(); if ((object as Mesh).isMesh && core_geometry) { const faces = core_geometry.faces(); // const points_count = core_geometry.pointsCount(); if (!core_geometry.hasAttrib(attrib_name)) { core_geometry.addNumericAttrib(attrib_name, 1, -1); } for (let i = 0; i < faces.length; i++) { const face = faces[i]; const points = face.points(); for (let j = 0; j < points.length; j++) { const point = points[j]; point.setAttribValue(attrib_name, i); } } } }); } private _transform_faces(core_group: CoreGroup) { const attrib_name = 'position'; const face_center = new Vector3(); const new_position = new Vector3(); const scale = this.pv.scale; let faces: CoreFace[], face: CoreFace, points: CorePoint[], point: CorePoint; core_group.coreObjects().forEach((core_object) => { const object = core_object.object(); const core_geometry = core_object.coreGeometry(); if ((object as Mesh).isMesh && core_geometry) { faces = core_geometry.faces(); if (!core_geometry.hasAttrib(attrib_name)) { core_geometry.addNumericAttrib(attrib_name, 3, -1); } for (let fi = 0; fi < faces.length; fi++) { face = faces[fi]; face.center(face_center); points = face.points(); for (let pi = 0; pi < points.length; pi++) { point = points[pi]; const position = point.position(); new_position.x = position.x * scale + face_center.x * (1 - scale); new_position.y = position.y * scale + face_center.y * (1 - scale); new_position.z = position.z * scale + face_center.z * (1 - scale); point.setAttribValue(attrib_name, new_position); } } } }); } }