I’ve been trying to import a few glb files (compressed with draco).
I am loading the meshes (groups), then taking the geometry and storing them in a custom mesh object I have added some functionality to so I can swap the geometries dynamicallly.
The raycaster itself does not seem to fail, as adding a cube into the scene does work.
The .glb files load fine, however I can’t get them to interact with the raycaster.
Below are what I think is the relevant code, if more context is required;
The project can be found here GitHub - ONiKi-Git/Configurator-Web
Mesh loading logic:
this.configurator.meshLibrary
.load('Body_Basic', 'assets/meshes/Seperate_Body_Basic.glb')
.subscribe((object) => {
//Get the loaded geometry
object.traverse((mesh) => {
if (mesh instanceof Mesh) {
this.body = new DynamicMesh(
mesh.geometry,
);
this.body.addOption('Body_Basic', {
geometry: mesh.geometry,
});
}
});
//add it to the scene
if (this.body) {
this.configurator.controller.scene.add(this.body);
}
});
the dynamic mesh class:
interface MeshInfo {
geometry: BufferGeometry;
material: Material;
offset?: Vector3;
}
export class DynamicMesh extends Mesh {
geometries: Map<string, MeshInfo> = new Map<string, MeshInfo>();
options: Array<string> = [];
initialized: Subject<string[]> = new Subject();
constructor(
public geometry: BufferGeometry,
public material: Material,
position: Vector3,
rotation: Vector3,
name: string = '',
) {
super();
this.name = name;
this.position.set(position.x, position.y, position.z);
this.rotation.setFromVector3(rotation);
this.geometry.computeBoundingBox();
}
addOption(id: string, meshInfo: MeshInfo) {
this.geometries.set(id, meshInfo);
this.options = [...this.geometries.keys()];
this.initialized.next(this.options);
}
setOption(meshID: string) {
if (this.geometries.has(meshID)) {
const entry = this.geometries.get(meshID)!;
this.geometry = entry.geometry;
this.material = entry.material;
if(entry.offset === undefined) {
entry.offset = new Vector3();
}
this.position.set(entry.offset.x, entry.offset.y, entry.offset.z);
} else {
console.warn(`${meshID} was not found on ${this.name}.`);
}
}
}
Lastly the actual mesh loading class, for context
interface MeshData {
group?: THREE.Group;
url: string;
name: string;
}
export class MeshLibrary {
data: Set<MeshData> = new Set<MeshData>();
constructor(private manager: LoadingManager) {
}
/**
* Consider loading materials separate to reduce load times on meshes
*/
load(
name: string,
url: string,
progressEvent: (progress: number) => void = () => {}
) {
var subject = new ReplaySubject<Group>();
var array = Array.from(this.data).filter((x) => x.url === url);
if (array.length == 0) {
new GLTFLoader(this.manager)
.loadAsync(url, (p) => {
//multiplied by 100 for angular/material progressbar
progressEvent((p.loaded / p.total) * 100);
})
.then((gltf) => {
this.data.add({ group: gltf.scene, url: url, name: name });
gltf.scene.name = name;
gltf.scene.traverse(x => {
if(x instanceof Mesh) {
x.geometry.computeBoundingBox();
}
})
subject.next(gltf.scene);
});
} else {
subject.next(array[0].group);
}
return subject;
}
}