import { Box3, Vector3, Group } from "three"; class MeshUtils { constructor(engine) { this.engine = engine; } assignParams(mesh, params){ ['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p])); [ 'visible', 'name', 'fontSize', 'color', 'lineHeight', 'maxWidth', 'anchorX', 'anchorY', 'outlineColor', 'outlineWidth', 'textAlign' ].forEach(p=>{ if (params[p]!==undefined) mesh[p] = params[p]; }); } assignMaterial(mesh, params){ if (params.name && params.material){ //let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material) Object.assign(mesh.material, params.material) if (params.dm){ this.engine.loadTexture(params.dm, params.path, undefined, [mesh.material, 'map']) // var dm = new TextureLoader().setPath(params.path).load(params.dm); // mesh.material.map = dm; } if (params.nm){ this.engine.loadTexture(params.nm, params.path, undefined, [mesh.material, 'normalMap']) //mesh.material.normalMap = new TextureLoader().setPath(params.path).load(params.nm); } if (params.em) { this.engine.loadTexture(params.em, params.path, undefined, [mesh.material, 'emissiveMap']) //mesh.material.emissiveMap = new TextureLoader().setPath(params.path).load(params.em); } //mesh.material = mp; mesh.material.needsUpdate = true; } } getBoundingBox(object){ let bb = new Box3().setFromObject(object); let scale = new Vector3(1,1,1); object.traverseAncestors(o=>{ scale.multiply(o.scale); }); bb.min.divide(scale); bb.max.divide(scale); return bb; } getBoundingBoxSize(bb){ return new Vector3(bb.max.x - bb.min.x, bb.max.y - bb.min.y, bb.max.z - bb.min.z); } getBoundingBoxMaxLength(bb){ let size = this.getBoundingBoxSize(bb) return Math.max(size.x, size.y, size.z) } getBoundingBoxCenterPoint(bb, relativeTo){ relativeTo = relativeTo || new Vector3(0,0,0) let size = this.getBoundingBoxSize(bb) return new Vector3( bb.min.x + (size.x)/2 - relativeTo.x, bb.min.y + (size.y)/2 - relativeTo.y, bb.min.z + (size.z)/2 - relativeTo.z ) } autoScale(object, mk = 1) { if (mk === null) return; let bb = this.getBoundingBox(object); let k = this.getBoundingBoxMaxLength(bb); object.scale.multiplyScalar(mk / k); } wrapInGroup(object){ if (object.isWrapper) return object; let group = new Group(); group.userData.bbox = this.getBoundingBox(object); group.add(object); group.userData.object = object; group.isWrapper = true; return group; } centerOrigin(object){ let group = this.wrapInGroup(object); let position = this.getBoundingBoxCenterPoint(group.userData.bbox, object.position).negate(); object.position.copy(position) return group; } bottomOrigin(object){ let group = this.centerOrigin(object); group.userData.object.position.y = -group.userData.bbox.min.y return group; } clearObject(o){ let disposables = [] o.traverse(object => { if (object.isMesh) { disposables.push(object); } if (object.isLight){ //console.log('Disposeing light', object) object.dispose(); object.shadow?.dispose(); object.shadow?.map?.dispose(); } if (object.userData?._io){ object.userData._io.dispose?.(); delete object.userData._io; } }); disposables.forEach(object=>{ object.removeFromParent(); object.geometry.dispose(); if (object.material.isMaterial) { this.clearMaterial(object.material) } else { for (const material of object.material) this.clearMaterial(material) } }) o.clear(); } clearMaterial(material) { material.dispose(); for (const key of Object.keys(material)) { const value = material[key] if (value && typeof value == 'object' && 'minFilter' in value) { //console.log('Disposing', value.name, this.renderer.info.memory.textures ); value.dispose(); //console.log('Disposed', value.name, this.renderer.info.memory.textures ); } } } } export { MeshUtils }