UNPKG

polygonjs-engine

Version:

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

96 lines (95 loc) 4 kB
import {BaseSopOperation} from "./_Base"; import {BufferGeometry as BufferGeometry2} from "three/src/core/BufferGeometry"; import {BufferAttribute as BufferAttribute2} from "three/src/core/BufferAttribute"; import {ObjectType} from "../../../core/geometry/Constant"; import {InputCloneMode as InputCloneMode2} from "../../../engine/poly/InputCloneMode"; import {CoreIterator} from "../../Iterator"; import {CoreMath} from "../../math/_Module"; import {CoreType} from "../../Type"; import {ArrayUtils as ArrayUtils2} from "../../ArrayUtils"; export class ScatterSopOperation extends BaseSopOperation { static type() { return "scatter"; } async cook(input_contents, params) { const core_group = input_contents[0]; let faces = core_group.faces(); const areas_thresholds = []; let area_sum = 0; const area_by_face_index = new Map(); for (let face of faces) { const area = face.area(); area_by_face_index.set(face.index(), area); } const sorted_faces = ArrayUtils2.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()); areas_thresholds[i] = area_sum; i++; } const positions = []; let attrib_names = []; if (params.transferAttributes) { attrib_names = core_group.attribNamesMatchingMask(params.attributesToTransfer); } const attrib_values_by_name = new Map(); const attrib_sizes_by_name = 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, (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 (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; } } }); const geometry = new BufferGeometry2(); geometry.setAttribute("position", new BufferAttribute2(new Float32Array(positions), 3)); for (let attrib_name of attrib_names) { geometry.setAttribute(attrib_name, new BufferAttribute2(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 = ArrayUtils2.range(pointsCount); if (params.addIdAttribute) { geometry.setAttribute("id", new BufferAttribute2(new Float32Array(ids), 1)); } const idns = ids.map((id) => id / (pointsCount - 1)); if (params.addIdnAttribute) { geometry.setAttribute("idn", new BufferAttribute2(new Float32Array(idns), 1)); } } const object = this.create_object(geometry, ObjectType.POINTS); return this.create_core_group_from_objects([object]); } } ScatterSopOperation.DEFAULT_PARAMS = { pointsCount: 100, seed: 0, transferAttributes: true, attributesToTransfer: "normal", addIdAttribute: true, addIdnAttribute: true }; ScatterSopOperation.INPUT_CLONED_STATE = InputCloneMode2.FROM_NODE;