threepipe
Version:
A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.
142 lines • 7.27 kB
JavaScript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrthographicCamera } from 'three';
import { safeSetProperty } from 'ts-browser-helpers';
import { generateUUID } from '../../three';
import { glbEncryptionPreparser, GLTFLightExtrasExtension, GLTFMaterialExtrasExtension, GLTFMaterialsAlphaMapExtension, GLTFMaterialsBumpMapExtension, GLTFMaterialsDisplacementMapExtension, GLTFMaterialsLightMapExtension, GLTFObject3DExtrasExtension, GLTFViewerConfigExtension, } from '../gltf';
import { ThreeSerialization } from '../../utils';
import { DirectionalLight2, PerspectiveCamera0, PhysicalMaterial, PointLight2, SpotLight2, UnlitLineMaterial, UnlitMaterial, } from '../../core';
export class GLTFLoader2 extends GLTFLoader {
constructor(manager) {
super(manager);
this.isGLTFLoader2 = true;
/**
* Preparsers are run on the arraybuffer/string before parsing to read the glb/gltf data
*/
this.preparsers = [];
// loads the viewer config and handles loading the draco loader for extension
this.gltfViewerParser = (viewer) => {
return (parser) => {
const getDependency = parser.getDependency;
parser.getDependency = async (type, index) => {
const res = await getDependency.call(parser, type, index);
if (res && res.userData) {
const gltfExtensions = res.userData.gltfExtensions;
delete res.userData.gltfExtensions;
res.userData = ThreeSerialization.Deserialize(res.userData, {});
res.userData.gltfExtensions = gltfExtensions;
}
return res;
};
const tempPathDrc = generateUUID() + '.drc';
const tempPathKtx2 = generateUUID() + '.ktx2';
const needsDrc = parser.json?.extensionsRequired?.includes?.('KHR_draco_mesh_compression');
if (needsDrc) {
const drc = viewer.assetManager.importer.registerFile(tempPathDrc);
drc && this.setDRACOLoader(drc); // todo: check class?
}
const needsMeshOpt = parser.json?.extensionsUsed?.includes?.('EXT_meshopt_compression');
if (needsMeshOpt) {
if (window.MeshoptDecoder) { // added by the plugin or by the user
this.setMeshoptDecoder(window.MeshoptDecoder);
parser.options.meshoptDecoder = window.MeshoptDecoder;
}
else {
console.error('Add GLTFMeshOptPlugin(and initialize it) to viewer to enable EXT_meshopt_compression decode');
}
}
const needsBasisU = parser.json?.extensionsUsed?.includes?.('KHR_texture_basisu');
if (needsBasisU) {
const ktx2 = viewer.assetManager.importer.registerFile(tempPathKtx2);
if (ktx2) {
this.setKTX2Loader(ktx2); // todo: check class?
parser.options.ktx2Loader = ktx2;
}
}
return { name: 'GLTF2_HELPER_PLUGIN', afterRoot: async (result) => {
if (needsDrc)
viewer.assetManager.importer.unregisterFile(tempPathDrc);
if (needsBasisU)
viewer.assetManager.importer.unregisterFile(tempPathKtx2);
await GLTFViewerConfigExtension.ImportViewerConfig(parser, viewer, result.scenes || [result.scene]);
} };
};
};
this.preparsers.push(glbEncryptionPreparser);
GLTFLoader.ObjectConstructors.DirectionalLight = DirectionalLight2;
GLTFLoader.ObjectConstructors.PointLight = PointLight2;
GLTFLoader.ObjectConstructors.SpotLight = SpotLight2;
GLTFLoader.ObjectConstructors.MeshStandardMaterial = PhysicalMaterial;
GLTFLoader.ObjectConstructors.MeshBasicMaterial = UnlitMaterial;
GLTFLoader.ObjectConstructors.MeshPhysicalMaterial = PhysicalMaterial;
GLTFLoader.ObjectConstructors.LineBasicMaterial = UnlitLineMaterial;
// GLTFLoader.ObjectConstructors.PointsMaterial = PointsMaterial2
GLTFLoader.ObjectConstructors.PerspectiveCamera = PerspectiveCamera0; // todo set domElement in the AssetManager during process
GLTFLoader.ObjectConstructors.OrthographicCamera = OrthographicCamera; // todo
}
async preparse(data, path) {
for (const preparser of this.preparsers) {
data = await preparser.process(data, path);
}
return data;
}
parse(data, path, onLoad, onError, url) {
this.preparse.call(this, data, url || path)
.then((res) => res ? super.parse(res, path, onLoad, onError) : onError && onError(new ErrorEvent('no data')))
.catch((e) => {
console.error(e);
if (onError)
onError(e ?? new ErrorEvent('unknown error'));
});
}
/**
* This is run post parse to extract the result scene from the GLTF object
* @param res
* @param _
*/
transform(res, _) {
// todo: support loading of multiple scenes?
const scene = res ? res.scene || !!res.scenes && res.scenes.length > 0 && res.scenes[0] : undefined;
if (!scene)
return undefined;
if (res.animations.length > 0)
scene.animations = res.animations;
scene.traverse((node) => {
if (node.userData.gltfUUID) { // saved in GLTFExporter2
safeSetProperty(node, 'uuid', node.userData.gltfUUID, true, true);
delete node.userData.gltfUUID; // have issue with cloning if we don't dispose.
}
});
// todo: replacing lights and camera, todo: remove and change constructors in GLTFLoader.js
if (!scene.userData)
scene.userData = {};
if (res.userData)
scene.userData.gltfExtras = res.userData; // todo: put back in gltf in GLTFExporter2
if (res.cameras)
res.cameras.forEach(c => !c.parent && scene.add(c));
if (res.asset)
scene.userData.gltfAsset = res.asset; // todo: put back in gltf in GLTFExporter2
return scene;
}
register(callback) {
return super.register(callback);
}
setup(viewer, extraExtensions) {
this.register(GLTFMaterialExtrasExtension.Import(viewer.loadConfigResources));
for (const ext of extraExtensions)
this.register(ext);
for (const ext of GLTFLoader2.ImportExtensions)
this.register(ext);
// Note: this should be last
this.register(this.gltfViewerParser(viewer));
return this;
}
}
GLTFLoader2.ImportExtensions = [
GLTFObject3DExtrasExtension.Import,
GLTFLightExtrasExtension.Import,
GLTFMaterialsBumpMapExtension.Import,
GLTFMaterialsDisplacementMapExtension.Import,
GLTFMaterialsLightMapExtension.Import,
GLTFMaterialsAlphaMapExtension.Import,
];
//# sourceMappingURL=GLTFLoader2.js.map