UNPKG

polygonjs-engine

Version:

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

162 lines (138 loc) 5.28 kB
import {BaseSopOperation} from './_Base'; import {CoreGroup} from '../../geometry/Group'; import {DefaultOperationParams} from '../_Base'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {BufferAttribute} from 'three/src/core/BufferAttribute'; import {ObjectType} from '../../../core/geometry/Constant'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {CoreIterator} from '../../Iterator'; import {CoreMath} from '../../math/_Module'; import {CoreType} from '../../Type'; import {ArrayUtils} from '../../ArrayUtils'; interface ScatterSopParams extends DefaultOperationParams { pointsCount: number; seed: number; transferAttributes: boolean; attributesToTransfer: string; addIdAttribute: boolean; addIdnAttribute: boolean; } export class ScatterSopOperation extends BaseSopOperation { static readonly DEFAULT_PARAMS: ScatterSopParams = { pointsCount: 100, seed: 0, transferAttributes: true, attributesToTransfer: 'normal', addIdAttribute: true, addIdnAttribute: true, }; static readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; static type(): Readonly<'scatter'> { return 'scatter'; } async cook(input_contents: CoreGroup[], params: ScatterSopParams) { const core_group = input_contents[0]; let faces = core_group.faces(); const areas_thresholds: number[] = []; let area_sum = 0; const area_by_face_index: Map<number, number> = new Map(); for (let face of faces) { const area = face.area(); area_by_face_index.set(face.index(), area); } const sorted_faces = ArrayUtils.sortBy(faces, (f) => { return area_by_face_index.get(f.index()) || -1; }); let i = 0; for (let face of sorted_faces) { area_sum += area_by_face_index.get(face.index()) as number; areas_thresholds[i] = area_sum; i++; } const positions: number[] = []; let attrib_names: string[] = []; if (params.transferAttributes) { attrib_names = core_group.attribNamesMatchingMask(params.attributesToTransfer); } const attrib_values_by_name: Map<string, number[]> = new Map(); const attrib_sizes_by_name: Map<string, number> = new Map(); for (let attrib_name of attrib_names) { attrib_values_by_name.set(attrib_name, []); attrib_sizes_by_name.set(attrib_name, core_group.attribSize(attrib_name)); } const iterator = new CoreIterator(); // await iterator.start_with_count(params.pointsCount, this._add_point.bind(this)) await iterator.start_with_count(params.pointsCount, (point_index: number) => { const rand = CoreMath.rand_float(params.seed + point_index) * area_sum; for (let face_index = 0; face_index < areas_thresholds.length; face_index++) { const areas_threshold = areas_thresholds[face_index]; if (rand <= areas_threshold) { const face = sorted_faces[face_index]; const position = face.random_position(rand); position.toArray(positions, positions.length); for (let attrib_name of attrib_names) { const attrib_value = face.attrib_value_at_position(attrib_name, position); if (attrib_value) { if (CoreType.isNumber(attrib_value)) { attrib_values_by_name.get(attrib_name)!.push(attrib_value); } else { attrib_value.toArray( attrib_values_by_name.get(attrib_name), attrib_values_by_name.get(attrib_name)!.length ); } } } break; } } }); // for(let point_index=0; point_index<params.pointsCount; point_index++){ // const rand = CoreMath.rand_float(params.seed+point_index) * area_sum // for(let face_index=0; face_index<areas_thresholds.length; face_index++){ // const areas_threshold = areas_thresholds[face_index] // if(rand <= areas_threshold){ // const face = sorted_faces[face_index] // const position = face.random_position(rand) // position.toArray(positions, positions.length) // for(let attrib_name of attrib_names){ // const attrib_value = face.attrib_value_at_position(attrib_name, position) // if (CoreType.isNumber(attrib_value)){ // attrib_values_by_name[attrib_name].push(attrib_value) // } else { // attrib_value.toArray( // attrib_values_by_name[attrib_name], // attrib_values_by_name[attrib_name].length // ) // } // } // break; // } // } // } const geometry = new BufferGeometry(); geometry.setAttribute('position', new BufferAttribute(new Float32Array(positions), 3)); for (let attrib_name of attrib_names) { geometry.setAttribute( attrib_name, new BufferAttribute( new Float32Array(attrib_values_by_name.get(attrib_name)!), attrib_sizes_by_name.get(attrib_name)! ) ); } if (params.addIdAttribute || params.addIdnAttribute) { const pointsCount = params.pointsCount; const ids = ArrayUtils.range(pointsCount); if (params.addIdAttribute) { geometry.setAttribute('id', new BufferAttribute(new Float32Array(ids), 1)); } const idns = ids.map((id) => id / (pointsCount - 1)); if (params.addIdnAttribute) { geometry.setAttribute('idn', new BufferAttribute(new Float32Array(idns), 1)); } } const object = this.create_object(geometry, ObjectType.POINTS); return this.create_core_group_from_objects([object]); } }