playcanvas
Version:
PlayCanvas WebGL game engine
118 lines (115 loc) • 3.58 kB
JavaScript
import { Asset } from '../asset/asset.js';
import { Http, http } from '../../platform/net/http.js';
import { GSplatResource } from '../../scene/gsplat/gsplat-resource.js';
import { GSplatSogsData } from '../../scene/gsplat/gsplat-sogs-data.js';
import { GSplatSogsResource } from '../../scene/gsplat/gsplat-sogs-resource.js';
const combineProgress = (target, assets)=>{
const map = new Map();
const fire = ()=>{
let loaded = 0;
let total = 0;
map.forEach((value)=>{
loaded += value.loaded;
total += value.total;
});
target.fire('progress', loaded, total);
};
assets.forEach((asset)=>{
const progress = (loaded, total)=>{
map.set(asset, {
loaded,
total
});
fire();
};
const done = ()=>{
asset.off('progress', progress);
asset.off('load', done);
asset.off('error', done);
};
asset.on('progress', progress);
asset.on('load', done);
asset.on('error', done);
});
};
class SogsParser {
constructor(app, maxRetries){
this.app = app;
this.maxRetries = maxRetries;
}
async loadTextures(url, callback, asset, meta) {
const { assets } = this.app;
const subs = [
'means',
'quats',
'scales',
'sh0',
'shN'
];
const textures = {};
const promises = [];
subs.forEach((sub)=>{
const files = meta[sub]?.files ?? [];
textures[sub] = files.map((filename)=>{
const texture = new Asset(filename, 'texture', {
url: asset.options?.mapUrl?.(filename) ?? new URL(filename, new URL(url.load, window.location.href).toString()).toString(),
filename
}, {
mipmaps: false
});
const promise = new Promise((resolve, reject)=>{
texture.on('load', ()=>resolve(null));
texture.on('error', (err)=>reject(err));
});
assets.add(texture);
promises.push(promise);
return texture;
});
});
const textureAssets = subs.map((sub)=>textures[sub]).flat();
combineProgress(asset, textureAssets);
textureAssets.forEach((t)=>assets.load(t));
await Promise.allSettled(promises);
const data = new GSplatSogsData();
data.meta = meta;
data.numSplats = meta.means.shape[0];
data.means_l = textures.means[0].resource;
data.means_u = textures.means[1].resource;
data.quats = textures.quats[0].resource;
data.scales = textures.scales[0].resource;
data.sh0 = textures.sh0[0].resource;
data.sh_centroids = textures.shN?.[0]?.resource;
data.sh_labels = textures.shN?.[1]?.resource;
const decompress = asset.data?.decompress;
if (!decompress) {
await data.prepareGpuData();
}
const resource = decompress ? new GSplatResource(this.app.graphicsDevice, await data.decompress()) : new GSplatSogsResource(this.app.graphicsDevice, data);
callback(null, resource);
}
load(url, callback, asset) {
if (asset.data?.means) {
this.loadTextures(url, callback, asset, asset.data);
} else {
if (typeof url === 'string') {
url = {
load: url,
original: url
};
}
const options = {
retry: this.maxRetries > 0,
maxRetries: this.maxRetries,
responseType: Http.ResponseType.JSON
};
http.get(url.load, options, (err, meta)=>{
if (!err) {
this.loadTextures(url, callback, asset, meta);
} else {
callback(`Error loading gsplat meta: ${url.original} [${err}]`);
}
});
}
}
}
export { SogsParser };