In our project, users can import files from a cloud/storage using a webDAV filepicker. On import, we pass the received and parsed blobs as File objects to our component hosting the Babylonjs scene. We implemented some very basic automatic peer/dependency finding in the said filepicker such that we pass the files to our viewer component in an array of objects (AssetFiles[]) where each one follows this format:
where, in the case of an .obj, file is the obj itself and peerFiles would be its material and textures.
Is there a tool available that can help me handle these files properly (using the OBJFileLoader?) to import them, make sure the materials and textures are applied to the correct meshes, pass them through a series of transformations I have (to rescale, remove empty vertices, and center) and to then add the resulting meshes to a predefined transformNode in our scene?
Am I mistaken for being wary of using URL.createObjectURL for the memory management part of things (keeping track of assets and revoking them when unused)?
Instead of passing files, I first tried using Tool.UseCustomRequestHeaders and setting the proper headers for authentication on Tool.CustomRequestHeaders, but I kept getting 401 errors which I think stem from the fact Angular is trying to handle the outgoing/incoming web requests.
So, I decided to try and connect Babylon directly with our file picker service using an override on the FileTools.RequestFile function to handle the web requests with our instance of angularās HttpClient, whenever the url points to the specific webDAV domain where the files are hosted. This way I could also define/use the dependency search from the SceneLoaderās plugins instead of in our filepicker. Hereās how Iām using our own requests sent through Angularās HttpClient (filepickerService.getFile() returns an RxJS observable bound to a get request with the proper headers) :
ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'onCompleteObservable' of undefined
Iām having a bit of trouble figuring out where/how this observable is managed. How could I bind my rxjs observableās resolution to the IFileRequest onCompleteObservable? Should I just overwrite RequestFileās default observable?
Yeah, my bad. I understand trying to figure things out through tiny excerpts of code from a much larger project is rarely fun or possible, sorry about that.
I did come across the post with the PreprocessUrl solution, but Iām not sure I grasp how that would work or how it could help me. Do you mean passing urls to the SceneLoader, and keeping track of which filename corresponds to which generated blob: url to then, in the preprocessor re-insert the proper blob: url? As in, for exemple:
That could work, but Iāll keep trying to figure out how to properly return and update the fileRequest observable in the RequestFile function as this seems like the best option since I could profit from the file loadersā automatic recovery of the needed .mtl and .textures in a better way than our filepicker does.
Somehow the requests are now working properly using CustomRequestHeaders, only problem Iām facing now is loading the textures, just like discussed here.
One hurdle is that our webDav endpoint isnāt configured in a way that is compatible with how the LoadImage seems to work by default (creating a new HTMLImageElement object by just setting the passed url as source, without making an actual CORS āGETā request) or with āuse-credentialsāā¦ and Iām not the one managing this NextCloud instance so modifying these settings isnāt an option at the moment. I tried various approaches, but the problem stays. Would there be a way to force an xhr FileRequest for images on babylonās side to then create the HTMLImageElement with the response blob without having to do the requests myself and replace the materials with new ones built afterwards to include the received image?
and hereās how Iām handling the import, where the main file (.obj for example) is pre-downloaded and passed to the babylonjs component as an Asset object*, containing the File with its remote (webdav) url:
*(I could also change this behavior to only pass a url and handle all requests with babylonās webrequests instead)
I thought forcing the basic auth credentials into the url would work, but alas.
Other than that, the .mtl file is requested properly and works just fine.
I can see there is a Tools.CorsBehaviour property and a Tools.SetCorsBehavior() function, maybe it can help somewhereā¦ However, Iām not very knowledgeable about url requests / CORS problems, letās see if others have some solutions for you.
-I canāt seem to find WebRequest.onload with babylonjsās xhr wrapper and response.onload isnāt the right thing (see update)
-The LoadImage function used by the scene loader isnāt accessible through FileTools.LoadImage nor Tools.LoadImage, hence the need to go through ThinEngine._FileToolsLoadImage. This doesnāt seem right.
ThinEngine._FileToolsLoadImage = (url, onload, onerror, database): HTMLImageElement => {
console.log('xhr image request : ' + url);
const img = new Image();
const imageRequest = new XMLHttpRequest();
imageRequest.open('GET', (url as string));
Object.entries(Cirrus.headersValues).forEach((header) => {
imageRequest.setRequestHeader(header[0], header[1]);
});
imageRequest.responseType = 'blob';
imageRequest.onload = () => {
img.src = URL.createObjectURL(imageRequest.response);
console.log(img);
};
imageRequest.send();
// Babylonjs Webrequest wrapper version (would profit from headers/settings set in global config)
// const img = new Image();
// const imageRequest = new WebRequest();
// imageRequest.open('GET', (url as string));
// imageRequest.responseType = 'blob';
// imageRequest.response.onload = () => {
// img.src = URL.createObjectURL(imageRequest.response);
// };
// imageRequest.send();
return img;
};
Using this, a request is sent and it is actually successful (200). But Something isnt working and the scene isnāt loading afterwards, Iāll keep looking into it.