Super cool. Thanks again donmccurdy !!
Just to confirm, strictly for learning purposes, the working solution actually involves no âfactoryâ pattern? It would have to involve new ModelLoader().loadModel()
? Or more specifically new ModelLoader().createLoadableModel()
or something like that? @emdax why were you asking for a factory specifically and not just a generic solution to the problem?
True â the solution I offerred did not use a Factory pattern. I assumed the OPâs suggestion of a Factory pattern was really attempting to clarify the question, rather than a hard requirement, and that simplicity was at least as valuable as the use of a specific OOP pattern.
For a large, complex project with many engineers, you might reasonably choose a more complex pattern in order to have consistency in the codebase â too many simple but inconsistent solutions create their own kind of complexity. And itâs those larger projects where I see Factory patterns. Totally a reasonable option, too, just somewhat less common in small projects.
Hi Don, would you mind helping me here? In your object cacher,
if ( models[ url ] ) {
return models[ url ].then( ( theMesh ) => {
theMesh.clone() ;
});
}
This works great! Very fast and efficient. However, the TEXTURE is still baked on to that object. Later on in my code, I am trying to apply a different texture, but it doesnât work. It looks like this is also cloning the texture. How can I strip it off?
This is how I am applying the texture later in the program:
gltf.traverse ( ( gltfObject ) => {
if ( gltfObject.isMesh ) {
// note: for a multi-material mesh, `o.material` may be an array,
// in which case you'd need to set `.map` on each value.
console.log("MAPPING THE TEXTURE");
gltfObject.material.map = texture;
}
} );
This doesnât work on cloned objects. Iâve tried to set the material.map = null, but nota.
I am trying to apply a different texture, but it doesnât work.
What result do you see, if it doesnât work? I assume you reuse an object multiple times, but the different instances are ending up with the same texture when you try to assign different textures to each?
When you clone an object, source.material === copy.material
. So you will need to manually clone the materials before trying to assign different textures.
Hrmm. Manually clear materials⌠Trying to figure out how and where exactly this takes place and what that looks like?
Care to share some psudo code example?
Edit: I see the same texture as the original model, despite trying to load a new texture onto the clone.
I think something like this would be the idea:
if ( models[ url ] ) {
return models[ url ].then( ( theMesh ) => {
const clone = theMesh.clone();
clone.traverse((o) => {
if (o.isMesh) o.material = o.material.clone();
});
return clone;
});
}
Ahhh yes â right on. But now I wish to replace that texture, on the clone.
Here:
gltf.traverse ( ( gltfObject ) => {
if ( gltfObject.isMesh ) {
// note: for a multi-material mesh, `o.material` may be an array,
// in which case you'd need to set `.map` on each value.
console.log("MAPPING THE TEXTURE");
gltfObject.material.map = texture;
}
} );
But this: gltfObject.material.map = texture;
Doesnât seem to work with the new texture. Will your above code fix this issue? Or am I not loading textures correctly on to the clone?
I think iâd need to reproduce what youâre doing to answer that. Can you create a demo of a simplified case?
Hey, i had a similar approach, but I had the problem that same objs which are loaded at the same time, will be stored multiple times. I made a function to remove all duplicates from the array, but I guess there must be a better way?
Also Im having a scene inside a Angular 2+ component which can be destroyed and revoked on button click. After clicking the button several times, my scene (or actually my computer) is starting to lag. Is it possible that the carbage collection is getting filled fast? Or where does this come from?
Im on a iMac 2009~ using Google Chrome
export class ModelManager {
static _instance: ModelManager
public models: { path: string, model: THREE.Object3D }[] = []
private loadingManager: THREE.LoadingManager
private gltfLoader: GLTFLoader
private nonLoaded: boolean
public onLoad: Function
public static instance() {
if(ModelManager._instance == null)
ModelManager._instance = new ModelManager()
return ModelManager._instance
}
constructor() {
this.nonLoaded = true
this.loadingManager = new THREE.LoadingManager()
this.gltfLoader = new GLTFLoader(this.loadingManager)
}
public load(path: string, onComplete: Function) {
let found: boolean = false
// onLoad callback
this.loadingManager.onLoad = ()=> {
if(this.onLoad != null && this.nonLoaded == false){
this.nonLoaded = true // Reset
this.onLoad()
}
}
// Check stored models for needed
if(this.models.length > 0) {
this.models.forEach(model => {
if(model.path == path) {
found = true
let clone = model.model.clone()
onComplete(clone)
}
})
}
// not found -> Load and store model
if(!found){
this.nonLoaded = false
this.loadGLTFModel(path, onComplete)
}
}
private loadGLTFModel(path: string, onLoad: Function) {
this.gltfLoader.load(path, (model)=> {
this.models.push({
path: path,
model: model.scene
})
if(this.models.length > 1)
this.models = Utility.removeDuplicates(this.models)
let clone = model.scene.clone()
onLoad(clone)
}, undefined, (error)=> {})
}
}