import * as THREE from "three"; export type VolatileGeometry = { mesh: THREE.Mesh, } export type VolatileGeometryBaseOptions = { color: THREE.ColorRepresentation, } export type VolatileGeometryPointOptions = VolatileGeometryBaseOptions & { kind: 'point', size: number, } export type VolatileGeometryCicleOptions = VolatileGeometryBaseOptions & { kind: 'circle', radius: number, thickness: number, } export type VolatileGeometryOptions = VolatileGeometryPointOptions | VolatileGeometryCicleOptions; export class VolatileGeometryHelper { private scene: THREE.Scene; private camera: THREE.PerspectiveCamera | THREE.OrthographicCamera; private readonly baseMaterial = new THREE.MeshBasicMaterial({ color: 'red' }); private readonly markers: Record = {}; constructor(scene: THREE.Scene, camera: THREE.PerspectiveCamera | THREE.OrthographicCamera) { this.scene = scene; this.camera = camera; } private createGeometry(options: VolatileGeometryOptions): THREE.BufferGeometry { switch (options.kind) { case 'point': return new THREE.SphereGeometry(options.size); case 'circle': return new THREE.TorusGeometry(options.radius, options.thickness * options.radius); default: throw new Error('Unknown volatile geometry type'); } } private ensure(id: string, options: VolatileGeometryOptions): VolatileGeometry { if (!this.markers[id]) { const material = this.baseMaterial.clone(); material.color.set(options.color); this.markers[id] = { mesh: new THREE.Mesh( this.createGeometry(options), material, ), }; this.scene.add(this.markers[id].mesh); } return this.markers[id]; } private disposeGeometry(id: string) { const point = this.markers[id]; if (point) { this.scene.remove(point.mesh); point.mesh.geometry.dispose(); delete (this.markers[id]); } } public dispose() { for (const id in this.markers) this.disposeGeometry(id); } public set(id: string, position: THREE.Vector3Like, options: VolatileGeometryOptions) { const point = this.ensure(id, options); // additional actions switch (options.kind) { case 'circle': point.mesh.lookAt(this.camera.position); break; } point.mesh.position.copy(position); } }