Back to home page

EIC code displayed by LXR

 
 

    


Warning, /firebird/firebird-ng/src/app/utils/three-geometry-merge.ts is written in an unsupported language. File is not indexed.

0001 import * as THREE from "three";
0002 import {mergeGeometries} from "three/examples/jsm/utils/BufferGeometryUtils";
0003 
0004 export interface MergeResult {
0005   mergedGeometry: THREE.BufferGeometry;
0006   mergedMesh: THREE.Mesh;
0007   material: THREE.Material | undefined;
0008   childrenToRemove: THREE.Object3D[];
0009   parentNode: THREE.Object3D;
0010 }
0011 
0012 export class NoGeometriesFoundError extends Error {
0013   constructor(message: string = "No geometries found in the provided node.") {
0014     super(message);
0015     this.name = "NoGeometriesFoundError";
0016   }
0017 }
0018 
0019 export class NoMaterialError extends Error {
0020   constructor(message: string = "No material set or found in geometries.") {
0021     super(message);
0022     this.name = "NoMaterialError";
0023   }
0024 }
0025 
0026 /**
0027  * Merges all geometries in a branch of the scene graph into a single geometry.
0028  * @param parentNode The parent node of the branch to merge.
0029  * @param name  Name of the new merged geometry node
0030  * @param material Material to assign to the merged geometry, if empty the first material found will be used
0031  * @returns MergeResult object containing the merged geometry, material, children to remove, and parent node
0032  */
0033 export function mergeBranchGeometries(parentNode: THREE.Object3D, name: string,  material?: THREE.Material | undefined): MergeResult {
0034   const geometries: THREE.BufferGeometry[] = [];
0035   const childrenToRemove: THREE.Object3D[] = [];
0036 
0037   // Recursively collect geometries from the branch
0038   const collectGeometries = (node: THREE.Object3D): void => {
0039     node.traverse((child: any) => {
0040 
0041       let isBufferGeometry = child?.geometry?.isBufferGeometry ?? false;
0042       //console.log(isBufferGeometry);
0043       if (isBufferGeometry) {
0044         child.updateMatrixWorld(true);
0045         const clonedGeometry = child.geometry.clone();
0046         clonedGeometry.applyMatrix4(child.matrixWorld);
0047         geometries.push(clonedGeometry);
0048         material = material || child.material;
0049         childrenToRemove.push(child);
0050       }
0051     });
0052   };
0053 
0054   collectGeometries(parentNode);
0055 
0056   if (geometries.length === 0) {
0057     throw new NoGeometriesFoundError();
0058   } else if (material === undefined) {
0059     throw new NoMaterialError();
0060   }
0061 
0062   // Merge all collected geometries
0063   const mergedGeometry = mergeGeometries(geometries, false);
0064 
0065   // Transform the merged geometry to the local space of the parent node
0066   const parentInverseMatrix = new THREE.Matrix4().copy(parentNode.matrixWorld).invert();
0067   mergedGeometry.applyMatrix4(parentInverseMatrix);
0068 
0069   // Create a new mesh with the merged geometry and the collected material
0070   const mergedMesh = new THREE.Mesh(mergedGeometry, material);
0071 
0072   // Remove the original children that are meshes and add the new merged mesh
0073   // Remove and dispose the original children
0074   childrenToRemove.forEach((child: any) => {
0075     child.geometry.dispose();
0076     child?.parent?.remove(child);
0077     // Remove empty parents
0078     if( (child?.parent?.children?.length ?? 1) === 0 ) {
0079       child?.parent?.parent?.remove(child.parent);
0080     }
0081   });
0082 
0083   mergedMesh.name = name;
0084 
0085   parentNode.add(mergedMesh);
0086   return {
0087     mergedGeometry,
0088     mergedMesh,
0089     material,
0090     childrenToRemove,
0091     parentNode
0092   };
0093 }
0094 
0095 
0096 /**
0097  * Merges all geometries from a list of meshes into a single geometry and attaches it to a new parent node.
0098  * @param meshes An array of THREE.Mesh objects whose geometries are to be merged.
0099  * @param parentNode The new parent node to which the merged mesh will be added.
0100  * @param name The name to assign to the merged mesh.
0101  *
0102  * (!) This function doesn't delete original meshes Compared to @see mergeBranchGeometries.
0103  * Use MergeResult.childrenToRemove to delete meshes that were merged
0104  *
0105  * @param material
0106  * @returns MergeResult The result of the merging process including the new parent node, merged geometry, material, and a list of original meshes.
0107  */
0108 export function mergeMeshList(meshes: THREE.Mesh[], parentNode: THREE.Object3D, name: string, material?: THREE.Material|undefined): MergeResult|undefined {
0109   const geometries: THREE.BufferGeometry[] = [];
0110 
0111   // Collect geometries and materials from the provided meshes
0112   meshes.forEach(mesh => {
0113     if (mesh?.geometry?.isBufferGeometry) {
0114       mesh.updateMatrixWorld(true);
0115       const clonedGeometry = mesh.geometry.clone();
0116       clonedGeometry.applyMatrix4(mesh.matrixWorld);
0117       geometries.push(clonedGeometry);
0118       // Check if mesh.material is an array and handle it
0119       if (!material) { // Only set if material has not been set yet
0120         if (Array.isArray(mesh.material)) {
0121           material = mesh.material[0]; // Use the first material if it's an array
0122         } else {
0123           material = mesh.material; // Use the material directly if it's not an array
0124         }
0125       }
0126     }
0127   });
0128 
0129   if (geometries.length === 0) {
0130     return undefined;
0131     //throw new NoGeometriesFoundError();
0132   }
0133   if (!material) {
0134     return undefined;
0135     //throw new NoMaterialError();
0136   }
0137 
0138   // Merge all collected geometries
0139   const mergedGeometry = mergeGeometries(geometries, false);
0140 
0141   // Transform the merged geometry to the local space of the parent node
0142   const parentInverseMatrix = new THREE.Matrix4().copy(parentNode.matrixWorld).invert();
0143   mergedGeometry.applyMatrix4(parentInverseMatrix);
0144 
0145   // Create a new mesh with the merged geometry and the collected material
0146   const mergedMesh = new THREE.Mesh(mergedGeometry, material);
0147   mergedMesh.name = name;
0148   parentNode.add(mergedMesh);
0149 
0150   return {
0151     mergedGeometry,
0152     mergedMesh,
0153     material,
0154     childrenToRemove: meshes, // Here, we assume the original meshes are what would be removed if needed
0155     parentNode
0156   };
0157 }