|
@@ -1,8 +1,8 @@
|
|
/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
|
|
/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
|
|
|
|
|
|
/**
|
|
/**
|
|
-* Defines the GLTF2 module used to import/export GLTF 2.0 files
|
|
|
|
-*/
|
|
|
|
|
|
+ * Defines the module used to import/export glTF 2.0 assets
|
|
|
|
+ */
|
|
module BABYLON.GLTF2 {
|
|
module BABYLON.GLTF2 {
|
|
interface IFileRequestInfo extends IFileRequest {
|
|
interface IFileRequestInfo extends IFileRequest {
|
|
_lengthComputable?: boolean;
|
|
_lengthComputable?: boolean;
|
|
@@ -10,37 +10,23 @@ module BABYLON.GLTF2 {
|
|
_total?: number;
|
|
_total?: number;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * Interface for a meterial with a constructor
|
|
|
|
- */
|
|
|
|
- export interface MaterialConstructor<T extends Material> {
|
|
|
|
- /**
|
|
|
|
- * The material class
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ export interface _MaterialConstructor<T extends Material> {
|
|
readonly prototype: T;
|
|
readonly prototype: T;
|
|
- /**
|
|
|
|
- * Instatiates a material
|
|
|
|
- * @param name name of the material
|
|
|
|
- * @param scene the scene the material will be added to
|
|
|
|
- */
|
|
|
|
new(name: string, scene: Scene): T;
|
|
new(name: string, scene: Scene): T;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Used to load from a GLTF2 file
|
|
|
|
- */
|
|
|
|
|
|
+ * Loader for loading a glTF 2.0 asset
|
|
|
|
+ */
|
|
export class GLTFLoader implements IGLTFLoader {
|
|
export class GLTFLoader implements IGLTFLoader {
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _gltf: ILoaderGLTF;
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _gltf: _ILoaderGLTF;
|
|
|
|
+
|
|
|
|
+ /** @hidden */
|
|
public _babylonScene: Scene;
|
|
public _babylonScene: Scene;
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+
|
|
|
|
+ /** @hidden */
|
|
public _completePromises = new Array<Promise<void>>();
|
|
public _completePromises = new Array<Promise<void>>();
|
|
|
|
|
|
private _disposed = false;
|
|
private _disposed = false;
|
|
@@ -48,18 +34,15 @@ module BABYLON.GLTF2 {
|
|
private _extensions: { [name: string]: GLTFLoaderExtension } = {};
|
|
private _extensions: { [name: string]: GLTFLoaderExtension } = {};
|
|
private _rootUrl: string;
|
|
private _rootUrl: string;
|
|
private _rootBabylonMesh: Mesh;
|
|
private _rootBabylonMesh: Mesh;
|
|
- private _defaultSampler = {} as ILoaderSampler;
|
|
|
|
|
|
+ private _defaultSampler = {} as _ILoaderSampler;
|
|
private _defaultBabylonMaterials: { [drawMode: number]: PBRMaterial } = {};
|
|
private _defaultBabylonMaterials: { [drawMode: number]: PBRMaterial } = {};
|
|
private _progressCallback?: (event: SceneLoaderProgressEvent) => void;
|
|
private _progressCallback?: (event: SceneLoaderProgressEvent) => void;
|
|
private _requests = new Array<IFileRequestInfo>();
|
|
private _requests = new Array<IFileRequestInfo>();
|
|
|
|
|
|
private static _Names = new Array<string>();
|
|
private static _Names = new Array<string>();
|
|
private static _Factories: { [name: string]: (loader: GLTFLoader) => GLTFLoaderExtension } = {};
|
|
private static _Factories: { [name: string]: (loader: GLTFLoader) => GLTFLoaderExtension } = {};
|
|
- /**
|
|
|
|
- * @ignore, registers the loader
|
|
|
|
- * @param name name of the loader
|
|
|
|
- * @param factory function that converts a loader to a loader extension
|
|
|
|
- */
|
|
|
|
|
|
+
|
|
|
|
+ /** @hidden */
|
|
public static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void {
|
|
public static _Register(name: string, factory: (loader: GLTFLoader) => GLTFLoaderExtension): void {
|
|
if (GLTFLoader._Factories[name]) {
|
|
if (GLTFLoader._Factories[name]) {
|
|
Tools.Error(`Extension with the name '${name}' already exists`);
|
|
Tools.Error(`Extension with the name '${name}' already exists`);
|
|
@@ -73,61 +56,79 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Coordinate system that will be used when loading from the gltf file
|
|
|
|
- */
|
|
|
|
|
|
+ * Mode that determines the coordinate system to use.
|
|
|
|
+ */
|
|
public coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
|
|
public coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Animation mode that determines which animations should be started when a file is loaded
|
|
|
|
- */
|
|
|
|
|
|
+ * Mode that determines what animations will start.
|
|
|
|
+ */
|
|
public animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
|
|
public animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * If the materials in the file should automatically be compiled
|
|
|
|
- */
|
|
|
|
|
|
+ * Defines if the loader should compile materials.
|
|
|
|
+ */
|
|
public compileMaterials = false;
|
|
public compileMaterials = false;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * If a clip plane should be usede when loading meshes in the file
|
|
|
|
- */
|
|
|
|
|
|
+ * Defines if the loader should also compile materials with clip planes.
|
|
|
|
+ */
|
|
public useClipPlane = false;
|
|
public useClipPlane = false;
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * If shadow generators should automatically be compiled
|
|
|
|
- */
|
|
|
|
|
|
+ * Defines if the loader should compile shadow generators.
|
|
|
|
+ */
|
|
public compileShadowGenerators = false;
|
|
public compileShadowGenerators = false;
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Observable that fires when the loader is disposed
|
|
|
|
- */
|
|
|
|
- public readonly onDisposeObservable = new Observable<IGLTFLoader>();
|
|
|
|
- /**
|
|
|
|
- * Observable that fires each time a mesh is loaded
|
|
|
|
- */
|
|
|
|
|
|
+ * Observable raised when the loader creates a mesh after parsing the glTF properties of the mesh.
|
|
|
|
+ */
|
|
public readonly onMeshLoadedObservable = new Observable<AbstractMesh>();
|
|
public readonly onMeshLoadedObservable = new Observable<AbstractMesh>();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Observable that fires each time a texture is loaded
|
|
|
|
- */
|
|
|
|
|
|
+ * Observable raised when the loader creates a texture after parsing the glTF properties of the texture.
|
|
|
|
+ */
|
|
public readonly onTextureLoadedObservable = new Observable<BaseTexture>();
|
|
public readonly onTextureLoadedObservable = new Observable<BaseTexture>();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Observable that fires each time a material is loaded
|
|
|
|
- */
|
|
|
|
|
|
+ * Observable raised when the loader creates a material after parsing the glTF properties of the material.
|
|
|
|
+ */
|
|
public readonly onMaterialLoadedObservable = new Observable<Material>();
|
|
public readonly onMaterialLoadedObservable = new Observable<Material>();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Observable that fires each time an extension is loaded
|
|
|
|
- */
|
|
|
|
- public readonly onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
|
|
|
|
|
|
+ * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
|
|
|
|
+ */
|
|
|
|
+ public readonly onCameraLoadedObservable = new Observable<Camera>();
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Observable that fires when the load has completed
|
|
|
|
- */
|
|
|
|
|
|
+ * Observable raised when the asset is completely loaded, immediately before the loader is disposed.
|
|
|
|
+ * For assets with LODs, raised when all of the LODs are complete.
|
|
|
|
+ * For assets without LODs, raised when the model is complete, immediately after the loader resolves the returned promise.
|
|
|
|
+ */
|
|
public readonly onCompleteObservable = new Observable<IGLTFLoader>();
|
|
public readonly onCompleteObservable = new Observable<IGLTFLoader>();
|
|
|
|
|
|
/**
|
|
/**
|
|
- * The current state of the loader
|
|
|
|
- */
|
|
|
|
|
|
+ * Observable raised after the loader is disposed.
|
|
|
|
+ */
|
|
|
|
+ public readonly onDisposeObservable = new Observable<IGLTFLoader>();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Observable raised after a loader extension is created.
|
|
|
|
+ * Set additional options for a loader extension in this event.
|
|
|
|
+ */
|
|
|
|
+ public readonly onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Loader state or null if the loader is not active.
|
|
|
|
+ */
|
|
public get state(): Nullable<GLTFLoaderState> {
|
|
public get state(): Nullable<GLTFLoaderState> {
|
|
return this._state;
|
|
return this._state;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Disposes of the loader
|
|
|
|
- */
|
|
|
|
|
|
+ * Disposes the loader, releases resources during load, and cancels any outstanding requests.
|
|
|
|
+ */
|
|
public dispose(): void {
|
|
public dispose(): void {
|
|
if (this._disposed) {
|
|
if (this._disposed) {
|
|
return;
|
|
return;
|
|
@@ -142,20 +143,20 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Imports one or more meshes from a loaded gltf file and adds them to the scene
|
|
|
|
- * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
|
|
|
|
- * @param scene the scene the meshes should be added to
|
|
|
|
- * @param data gltf data containing information of the meshes in a loaded file
|
|
|
|
- * @param rootUrl root url to load from
|
|
|
|
- * @param onProgress event that fires when loading progress has occured
|
|
|
|
- * @returns a promise containg the loaded meshes, particles, skeletons and animations
|
|
|
|
- */
|
|
|
|
|
|
+ * Imports one or more meshes from the loaded glTF data and adds them to the scene
|
|
|
|
+ * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
|
|
|
|
+ * @param scene the scene the meshes should be added to
|
|
|
|
+ * @param data the glTF data to load
|
|
|
|
+ * @param rootUrl root url to load from
|
|
|
|
+ * @param onProgress event that fires when loading progress has occured
|
|
|
|
+ * @returns a promise containg the loaded meshes, particles, skeletons and animations
|
|
|
|
+ */
|
|
public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[] }> {
|
|
public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[] }> {
|
|
return Promise.resolve().then(() => {
|
|
return Promise.resolve().then(() => {
|
|
- let nodes: Nullable<Array<ILoaderNode>> = null;
|
|
|
|
|
|
+ let nodes: Nullable<Array<_ILoaderNode>> = null;
|
|
|
|
|
|
if (meshesNames) {
|
|
if (meshesNames) {
|
|
- const nodeMap: { [name: string]: ILoaderNode } = {};
|
|
|
|
|
|
+ const nodeMap: { [name: string]: _ILoaderNode } = {};
|
|
if (this._gltf.nodes) {
|
|
if (this._gltf.nodes) {
|
|
for (const node of this._gltf.nodes) {
|
|
for (const node of this._gltf.nodes) {
|
|
if (node.name) {
|
|
if (node.name) {
|
|
@@ -187,18 +188,18 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Imports all objects from a loaded gltf file and adds them to the scene
|
|
|
|
- * @param scene the scene the objects should be added to
|
|
|
|
- * @param data gltf data containing information of the meshes in a loaded file
|
|
|
|
- * @param rootUrl root url to load from
|
|
|
|
- * @param onProgress event that fires when loading progress has occured
|
|
|
|
- * @returns a promise which completes when objects have been loaded to the scene
|
|
|
|
- */
|
|
|
|
|
|
+ * Imports all objects from the loaded glTF data and adds them to the scene
|
|
|
|
+ * @param scene the scene the objects should be added to
|
|
|
|
+ * @param data the glTF data to load
|
|
|
|
+ * @param rootUrl root url to load from
|
|
|
|
+ * @param onProgress event that fires when loading progress has occured
|
|
|
|
+ * @returns a promise which completes when objects have been loaded to the scene
|
|
|
|
+ */
|
|
public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
|
|
public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
|
|
return this._loadAsync(null, scene, data, rootUrl, onProgress);
|
|
return this._loadAsync(null, scene, data, rootUrl, onProgress);
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadAsync(nodes: Nullable<Array<ILoaderNode>>, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
|
|
|
|
|
|
+ private _loadAsync(nodes: Nullable<Array<_ILoaderNode>>, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void> {
|
|
return Promise.resolve().then(() => {
|
|
return Promise.resolve().then(() => {
|
|
this._loadExtensions();
|
|
this._loadExtensions();
|
|
|
|
|
|
@@ -271,7 +272,7 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
private _loadData(data: IGLTFLoaderData): void {
|
|
private _loadData(data: IGLTFLoaderData): void {
|
|
- this._gltf = data.json as ILoaderGLTF;
|
|
|
|
|
|
+ this._gltf = data.json as _ILoaderGLTF;
|
|
this._setupData();
|
|
this._setupData();
|
|
|
|
|
|
if (data.bin) {
|
|
if (data.bin) {
|
|
@@ -291,19 +292,19 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
private _setupData(): void {
|
|
private _setupData(): void {
|
|
- ArrayItem.Assign(this._gltf.accessors);
|
|
|
|
- ArrayItem.Assign(this._gltf.animations);
|
|
|
|
- ArrayItem.Assign(this._gltf.buffers);
|
|
|
|
- ArrayItem.Assign(this._gltf.bufferViews);
|
|
|
|
- ArrayItem.Assign(this._gltf.cameras);
|
|
|
|
- ArrayItem.Assign(this._gltf.images);
|
|
|
|
- ArrayItem.Assign(this._gltf.materials);
|
|
|
|
- ArrayItem.Assign(this._gltf.meshes);
|
|
|
|
- ArrayItem.Assign(this._gltf.nodes);
|
|
|
|
- ArrayItem.Assign(this._gltf.samplers);
|
|
|
|
- ArrayItem.Assign(this._gltf.scenes);
|
|
|
|
- ArrayItem.Assign(this._gltf.skins);
|
|
|
|
- ArrayItem.Assign(this._gltf.textures);
|
|
|
|
|
|
+ _ArrayItem.Assign(this._gltf.accessors);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.animations);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.buffers);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.bufferViews);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.cameras);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.images);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.materials);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.meshes);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.nodes);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.samplers);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.scenes);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.skins);
|
|
|
|
+ _ArrayItem.Assign(this._gltf.textures);
|
|
|
|
|
|
if (this._gltf.nodes) {
|
|
if (this._gltf.nodes) {
|
|
const nodeParents: { [index: number]: number } = {};
|
|
const nodeParents: { [index: number]: number } = {};
|
|
@@ -334,11 +335,11 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private _createRootNode(): ILoaderNode {
|
|
|
|
|
|
+ private _createRootNode(): _ILoaderNode {
|
|
this._rootBabylonMesh = new Mesh("__root__", this._babylonScene);
|
|
this._rootBabylonMesh = new Mesh("__root__", this._babylonScene);
|
|
this._rootBabylonMesh.setEnabled(false);
|
|
this._rootBabylonMesh.setEnabled(false);
|
|
|
|
|
|
- const rootNode = { _babylonMesh: this._rootBabylonMesh } as ILoaderNode;
|
|
|
|
|
|
+ const rootNode = { _babylonMesh: this._rootBabylonMesh } as _ILoaderNode;
|
|
switch (this.coordinateSystemMode) {
|
|
switch (this.coordinateSystemMode) {
|
|
case GLTFLoaderCoordinateSystemMode.AUTO: {
|
|
case GLTFLoaderCoordinateSystemMode.AUTO: {
|
|
if (!this._babylonScene.useRightHandedSystem) {
|
|
if (!this._babylonScene.useRightHandedSystem) {
|
|
@@ -361,7 +362,7 @@ module BABYLON.GLTF2 {
|
|
return rootNode;
|
|
return rootNode;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadNodesAsync(nodes: ILoaderNode[], ): Promise<void> {
|
|
|
|
|
|
+ private _loadNodesAsync(nodes: _ILoaderNode[], ): Promise<void> {
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
for (let node of nodes) {
|
|
for (let node of nodes) {
|
|
@@ -373,10 +374,8 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void> {
|
|
const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
|
|
const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
|
|
if (promise) {
|
|
if (promise) {
|
|
return promise;
|
|
return promise;
|
|
@@ -394,7 +393,7 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private _forEachPrimitive(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
|
|
|
|
|
|
+ private _forEachPrimitive(node: _ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
|
|
if (node._primitiveBabylonMeshes) {
|
|
if (node._primitiveBabylonMeshes) {
|
|
for (const babylonMesh of node._primitiveBabylonMeshes) {
|
|
for (const babylonMesh of node._primitiveBabylonMeshes) {
|
|
callback(babylonMesh);
|
|
callback(babylonMesh);
|
|
@@ -486,10 +485,8 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadNodeAsync(context: string, node: ILoaderNode): Promise<void> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadNodeAsync(context: string, node: _ILoaderNode): Promise<void> {
|
|
const promise = GLTFLoaderExtension._LoadNodeAsync(this, context, node);
|
|
const promise = GLTFLoaderExtension._LoadNodeAsync(this, context, node);
|
|
if (promise) {
|
|
if (promise) {
|
|
return promise;
|
|
return promise;
|
|
@@ -514,6 +511,11 @@ module BABYLON.GLTF2 {
|
|
promises.push(this._loadMeshAsync(`#/meshes/${mesh._index}`, node, mesh, babylonMesh));
|
|
promises.push(this._loadMeshAsync(`#/meshes/${mesh._index}`, node, mesh, babylonMesh));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (node.camera != undefined) {
|
|
|
|
+ const camera = GLTFLoader._GetProperty(`${context}/camera`, this._gltf.cameras, node.camera);
|
|
|
|
+ this._loadCamera(`#/cameras/${camera._index}`, camera, babylonMesh);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (node.children) {
|
|
if (node.children) {
|
|
for (const index of node.children) {
|
|
for (const index of node.children) {
|
|
const childNode = GLTFLoader._GetProperty(`${context}/children/${index}`, this._gltf.nodes, index);
|
|
const childNode = GLTFLoader._GetProperty(`${context}/children/${index}`, this._gltf.nodes, index);
|
|
@@ -526,7 +528,7 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadMeshAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, babylonMesh: Mesh): Promise<void> {
|
|
|
|
|
|
+ private _loadMeshAsync(context: string, node: _ILoaderNode, mesh: _ILoaderMesh, babylonMesh: Mesh): Promise<void> {
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
const primitives = mesh.primitives;
|
|
const primitives = mesh.primitives;
|
|
@@ -534,7 +536,7 @@ module BABYLON.GLTF2 {
|
|
throw new Error(`${context}: Primitives are missing`);
|
|
throw new Error(`${context}: Primitives are missing`);
|
|
}
|
|
}
|
|
|
|
|
|
- ArrayItem.Assign(primitives);
|
|
|
|
|
|
+ _ArrayItem.Assign(primitives);
|
|
if (primitives.length === 1) {
|
|
if (primitives.length === 1) {
|
|
const primitive = primitives[0];
|
|
const primitive = primitives[0];
|
|
promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, babylonMesh));
|
|
promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, babylonMesh));
|
|
@@ -561,7 +563,7 @@ module BABYLON.GLTF2 {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadPrimitiveAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<void> {
|
|
|
|
|
|
+ private _loadPrimitiveAsync(context: string, node: _ILoaderNode, mesh: _ILoaderMesh, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<void> {
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
|
|
this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
|
|
@@ -585,7 +587,7 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<Geometry> {
|
|
|
|
|
|
+ private _loadVertexDataAsync(context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Promise<Geometry> {
|
|
const promise = GLTFLoaderExtension._LoadVertexDataAsync(this, context, primitive, babylonMesh);
|
|
const promise = GLTFLoaderExtension._LoadVertexDataAsync(this, context, primitive, babylonMesh);
|
|
if (promise) {
|
|
if (promise) {
|
|
return promise;
|
|
return promise;
|
|
@@ -605,12 +607,12 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
const accessor = GLTFLoader._GetProperty(context + "/indices", this._gltf.accessors, primitive.indices);
|
|
const accessor = GLTFLoader._GetProperty(context + "/indices", this._gltf.accessors, primitive.indices);
|
|
- promises.push(this._loadAccessorAsync("#/accessors/" + accessor._index, accessor).then(data => {
|
|
|
|
- babylonGeometry.setIndices(data as IndicesArray);
|
|
|
|
|
|
+ promises.push(this._loadIndicesAccessorAsync("#/accessors/" + accessor._index, accessor).then(data => {
|
|
|
|
+ babylonGeometry.setIndices(data);
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
|
|
|
|
- const loadAttribute = (attribute: string, kind: string, callback?: (accessor: ILoaderAccessor) => void) => {
|
|
|
|
|
|
+ const loadAttribute = (attribute: string, kind: string, callback?: (accessor: _ILoaderAccessor) => void) => {
|
|
if (attributes[attribute] == undefined) {
|
|
if (attributes[attribute] == undefined) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -648,7 +650,7 @@ module BABYLON.GLTF2 {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- private _createMorphTargets(context: string, node: ILoaderNode, mesh: ILoaderMesh, primitive: IMeshPrimitive, babylonMesh: Mesh): void {
|
|
|
|
|
|
+ private _createMorphTargets(context: string, node: _ILoaderNode, mesh: _ILoaderMesh, primitive: IMeshPrimitive, babylonMesh: Mesh): void {
|
|
if (!primitive.targets) {
|
|
if (!primitive.targets) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -698,11 +700,7 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
|
|
|
|
const accessor = GLTFLoader._GetProperty(`${context}/${attribute}`, this._gltf.accessors, attributes[attribute]);
|
|
const accessor = GLTFLoader._GetProperty(`${context}/${attribute}`, this._gltf.accessors, attributes[attribute]);
|
|
- promises.push(this._loadAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
|
|
|
|
- if (!(data instanceof Float32Array)) {
|
|
|
|
- throw new Error(`${context}: Morph target accessor must have float data`);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ promises.push(this._loadFloatAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
|
|
setData(babylonVertexBuffer, data);
|
|
setData(babylonVertexBuffer, data);
|
|
}));
|
|
}));
|
|
};
|
|
};
|
|
@@ -739,7 +737,7 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private static _LoadTransform(node: ILoaderNode, babylonNode: TransformNode): void {
|
|
|
|
|
|
+ private static _LoadTransform(node: _ILoaderNode, babylonNode: TransformNode): void {
|
|
let position = Vector3.Zero();
|
|
let position = Vector3.Zero();
|
|
let rotation = Quaternion.Identity();
|
|
let rotation = Quaternion.Identity();
|
|
let scaling = Vector3.One();
|
|
let scaling = Vector3.One();
|
|
@@ -759,7 +757,7 @@ module BABYLON.GLTF2 {
|
|
babylonNode.scaling = scaling;
|
|
babylonNode.scaling = scaling;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadSkinAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, skin: ILoaderSkin): Promise<void> {
|
|
|
|
|
|
+ private _loadSkinAsync(context: string, node: _ILoaderNode, mesh: _ILoaderMesh, skin: _ILoaderSkin): Promise<void> {
|
|
const assignSkeleton = (skeleton: Skeleton) => {
|
|
const assignSkeleton = (skeleton: Skeleton) => {
|
|
this._forEachPrimitive(node, babylonMesh => {
|
|
this._forEachPrimitive(node, babylonMesh => {
|
|
babylonMesh.skeleton = skeleton;
|
|
babylonMesh.skeleton = skeleton;
|
|
@@ -790,7 +788,7 @@ module BABYLON.GLTF2 {
|
|
}));
|
|
}));
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadBones(context: string, skin: ILoaderSkin): void {
|
|
|
|
|
|
+ private _loadBones(context: string, skin: _ILoaderSkin): void {
|
|
const babylonBones: { [index: number]: Bone } = {};
|
|
const babylonBones: { [index: number]: Bone } = {};
|
|
for (const index of skin.joints) {
|
|
for (const index of skin.joints) {
|
|
const node = GLTFLoader._GetProperty(`${context}/joints/${index}`, this._gltf.nodes, index);
|
|
const node = GLTFLoader._GetProperty(`${context}/joints/${index}`, this._gltf.nodes, index);
|
|
@@ -798,7 +796,7 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadBone(node: ILoaderNode, skin: ILoaderSkin, babylonBones: { [index: number]: Bone }): Bone {
|
|
|
|
|
|
+ private _loadBone(node: _ILoaderNode, skin: _ILoaderSkin, babylonBones: { [index: number]: Bone }): Bone {
|
|
let babylonBone = babylonBones[node._index];
|
|
let babylonBone = babylonBones[node._index];
|
|
if (babylonBone) {
|
|
if (babylonBone) {
|
|
return babylonBone;
|
|
return babylonBone;
|
|
@@ -820,15 +818,13 @@ module BABYLON.GLTF2 {
|
|
return babylonBone;
|
|
return babylonBone;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadSkinInverseBindMatricesDataAsync(context: string, skin: ILoaderSkin): Promise<Nullable<Float32Array>> {
|
|
|
|
|
|
+ private _loadSkinInverseBindMatricesDataAsync(context: string, skin: _ILoaderSkin): Promise<Nullable<Float32Array>> {
|
|
if (skin.inverseBindMatrices == undefined) {
|
|
if (skin.inverseBindMatrices == undefined) {
|
|
return Promise.resolve(null);
|
|
return Promise.resolve(null);
|
|
}
|
|
}
|
|
|
|
|
|
const accessor = GLTFLoader._GetProperty(`${context}/inverseBindMatrices`, this._gltf.accessors, skin.inverseBindMatrices);
|
|
const accessor = GLTFLoader._GetProperty(`${context}/inverseBindMatrices`, this._gltf.accessors, skin.inverseBindMatrices);
|
|
- return this._loadAccessorAsync(`#/accessors/${accessor._index}`, accessor).then(data => {
|
|
|
|
- return data as Float32Array;
|
|
|
|
- });
|
|
|
|
|
|
+ return this._loadFloatAccessorAsync(`#/accessors/${accessor._index}`, accessor);
|
|
}
|
|
}
|
|
|
|
|
|
private _updateBoneMatrices(babylonSkeleton: Skeleton, inverseBindMatricesData: Nullable<Float32Array>): void {
|
|
private _updateBoneMatrices(babylonSkeleton: Skeleton, inverseBindMatricesData: Nullable<Float32Array>): void {
|
|
@@ -850,7 +846,7 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private _getNodeMatrix(node: ILoaderNode): Matrix {
|
|
|
|
|
|
+ private _getNodeMatrix(node: _ILoaderNode): Matrix {
|
|
return node.matrix ?
|
|
return node.matrix ?
|
|
Matrix.FromArray(node.matrix) :
|
|
Matrix.FromArray(node.matrix) :
|
|
Matrix.Compose(
|
|
Matrix.Compose(
|
|
@@ -859,6 +855,45 @@ module BABYLON.GLTF2 {
|
|
node.translation ? Vector3.FromArray(node.translation) : Vector3.Zero());
|
|
node.translation ? Vector3.FromArray(node.translation) : Vector3.Zero());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private _loadCamera(context: string, camera: _ILoaderCamera, babylonMesh: Mesh): void {
|
|
|
|
+ const babylonCamera = new FreeCamera(camera.name || `camera${camera._index}`, Vector3.Zero(), this._babylonScene, false);
|
|
|
|
+ babylonCamera.parent = babylonMesh;
|
|
|
|
+ babylonCamera.rotation = new Vector3(0, Math.PI, 0);
|
|
|
|
+
|
|
|
|
+ switch (camera.type) {
|
|
|
|
+ case CameraType.PERSPECTIVE: {
|
|
|
|
+ const perspective = camera.perspective;
|
|
|
|
+ if (!perspective) {
|
|
|
|
+ throw new Error(`${context}: Camera perspective properties are missing`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ babylonCamera.fov = perspective.yfov;
|
|
|
|
+ babylonCamera.minZ = perspective.znear;
|
|
|
|
+ babylonCamera.maxZ = perspective.zfar || Number.MAX_VALUE;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ case CameraType.ORTHOGRAPHIC: {
|
|
|
|
+ if (!camera.orthographic) {
|
|
|
|
+ throw new Error(`${context}: Camera orthographic properties are missing`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ babylonCamera.mode = Camera.ORTHOGRAPHIC_CAMERA;
|
|
|
|
+ babylonCamera.orthoLeft = -camera.orthographic.xmag;
|
|
|
|
+ babylonCamera.orthoRight = camera.orthographic.xmag;
|
|
|
|
+ babylonCamera.orthoBottom = -camera.orthographic.ymag;
|
|
|
|
+ babylonCamera.orthoTop = camera.orthographic.ymag;
|
|
|
|
+ babylonCamera.minZ = camera.orthographic.znear;
|
|
|
|
+ babylonCamera.maxZ = camera.orthographic.zfar;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default: {
|
|
|
|
+ throw new Error(`${context}: Invalid camera type (${camera.type})`);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.onCameraLoadedObservable.notifyObservers(babylonCamera);
|
|
|
|
+ }
|
|
|
|
+
|
|
private _loadAnimationsAsync(): Promise<void> {
|
|
private _loadAnimationsAsync(): Promise<void> {
|
|
const animations = this._gltf.animations;
|
|
const animations = this._gltf.animations;
|
|
if (!animations) {
|
|
if (!animations) {
|
|
@@ -875,14 +910,14 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadAnimationAsync(context: string, animation: ILoaderAnimation): Promise<void> {
|
|
|
|
|
|
+ private _loadAnimationAsync(context: string, animation: _ILoaderAnimation): Promise<void> {
|
|
const babylonAnimationGroup = new AnimationGroup(animation.name || `animation${animation._index}`, this._babylonScene);
|
|
const babylonAnimationGroup = new AnimationGroup(animation.name || `animation${animation._index}`, this._babylonScene);
|
|
animation._babylonAnimationGroup = babylonAnimationGroup;
|
|
animation._babylonAnimationGroup = babylonAnimationGroup;
|
|
|
|
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
- ArrayItem.Assign(animation.channels);
|
|
|
|
- ArrayItem.Assign(animation.samplers);
|
|
|
|
|
|
+ _ArrayItem.Assign(animation.channels);
|
|
|
|
+ _ArrayItem.Assign(animation.samplers);
|
|
|
|
|
|
for (const channel of animation.channels) {
|
|
for (const channel of animation.channels) {
|
|
promises.push(this._loadAnimationChannelAsync(`${context}/channels/${channel._index}`, context, animation, channel, babylonAnimationGroup));
|
|
promises.push(this._loadAnimationChannelAsync(`${context}/channels/${channel._index}`, context, animation, channel, babylonAnimationGroup));
|
|
@@ -893,9 +928,12 @@ module BABYLON.GLTF2 {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadAnimationChannelAsync(context: string, animationContext: string, animation: ILoaderAnimation, channel: ILoaderAnimationChannel, babylonAnimationGroup: AnimationGroup): Promise<void> {
|
|
|
|
|
|
+ private _loadAnimationChannelAsync(context: string, animationContext: string, animation: _ILoaderAnimation, channel: _ILoaderAnimationChannel, babylonAnimationGroup: AnimationGroup): Promise<void> {
|
|
const targetNode = GLTFLoader._GetProperty(`${context}/target/node`, this._gltf.nodes, channel.target.node);
|
|
const targetNode = GLTFLoader._GetProperty(`${context}/target/node`, this._gltf.nodes, channel.target.node);
|
|
- if (!targetNode._babylonMesh) {
|
|
|
|
|
|
+
|
|
|
|
+ // Ignore animations that have no animation targets.
|
|
|
|
+ if ((channel.target.path === AnimationChannelTargetPath.WEIGHTS && !targetNode._numMorphTargets) ||
|
|
|
|
+ (channel.target.path !== AnimationChannelTargetPath.WEIGHTS && !targetNode._babylonAnimationTargets)) {
|
|
return Promise.resolve();
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1044,7 +1082,7 @@ module BABYLON.GLTF2 {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadAnimationSamplerAsync(context: string, sampler: ILoaderAnimationSampler): Promise<ILoaderAnimationSamplerData> {
|
|
|
|
|
|
+ private _loadAnimationSamplerAsync(context: string, sampler: _ILoaderAnimationSampler): Promise<_ILoaderAnimationSamplerData> {
|
|
if (sampler._data) {
|
|
if (sampler._data) {
|
|
return sampler._data;
|
|
return sampler._data;
|
|
}
|
|
}
|
|
@@ -1061,31 +1099,24 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- let inputData: Nullable<Float32Array>;
|
|
|
|
- let outputData: Nullable<Float32Array>;
|
|
|
|
-
|
|
|
|
const inputAccessor = GLTFLoader._GetProperty(`${context}/input`, this._gltf.accessors, sampler.input);
|
|
const inputAccessor = GLTFLoader._GetProperty(`${context}/input`, this._gltf.accessors, sampler.input);
|
|
const outputAccessor = GLTFLoader._GetProperty(`${context}/output`, this._gltf.accessors, sampler.output);
|
|
const outputAccessor = GLTFLoader._GetProperty(`${context}/output`, this._gltf.accessors, sampler.output);
|
|
|
|
|
|
sampler._data = Promise.all([
|
|
sampler._data = Promise.all([
|
|
- this._loadAccessorAsync(`#/accessors/${inputAccessor._index}`, inputAccessor).then(data => {
|
|
|
|
- inputData = data as Float32Array;
|
|
|
|
- }),
|
|
|
|
- this._loadAccessorAsync(`#/accessors/${outputAccessor._index}`, outputAccessor).then(data => {
|
|
|
|
- outputData = data as Float32Array;
|
|
|
|
- })
|
|
|
|
- ]).then(() => {
|
|
|
|
|
|
+ this._loadFloatAccessorAsync(`#/accessors/${inputAccessor._index}`, inputAccessor),
|
|
|
|
+ this._loadFloatAccessorAsync(`#/accessors/${outputAccessor._index}`, outputAccessor)
|
|
|
|
+ ]).then(([inputData, outputData]) => {
|
|
return {
|
|
return {
|
|
- input: inputData!,
|
|
|
|
|
|
+ input: inputData,
|
|
interpolation: interpolation,
|
|
interpolation: interpolation,
|
|
- output: outputData!,
|
|
|
|
|
|
+ output: outputData,
|
|
};
|
|
};
|
|
});
|
|
});
|
|
|
|
|
|
return sampler._data;
|
|
return sampler._data;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadBufferAsync(context: string, buffer: ILoaderBuffer): Promise<ArrayBufferView> {
|
|
|
|
|
|
+ private _loadBufferAsync(context: string, buffer: _ILoaderBuffer): Promise<ArrayBufferView> {
|
|
if (buffer._data) {
|
|
if (buffer._data) {
|
|
return buffer._data;
|
|
return buffer._data;
|
|
}
|
|
}
|
|
@@ -1099,16 +1130,14 @@ module BABYLON.GLTF2 {
|
|
return buffer._data;
|
|
return buffer._data;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadBufferViewAsync(context: string, bufferView: ILoaderBufferView): Promise<ArrayBufferView> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadBufferViewAsync(context: string, bufferView: _ILoaderBufferView): Promise<ArrayBufferView> {
|
|
if (bufferView._data) {
|
|
if (bufferView._data) {
|
|
return bufferView._data;
|
|
return bufferView._data;
|
|
}
|
|
}
|
|
|
|
|
|
- const buffer = GLTFLoader._GetProperty(context + "/buffer", this._gltf.buffers, bufferView.buffer);
|
|
|
|
- bufferView._data = this._loadBufferAsync("#/buffers/" + buffer._index, buffer).then(data => {
|
|
|
|
|
|
+ const buffer = GLTFLoader._GetProperty(`${context}/buffer`, this._gltf.buffers, bufferView.buffer);
|
|
|
|
+ bufferView._data = this._loadBufferAsync(`#/buffers/${buffer._index}`, buffer).then(data => {
|
|
try {
|
|
try {
|
|
return new Uint8Array(data.buffer, data.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
|
|
return new Uint8Array(data.buffer, data.byteOffset + (bufferView.byteOffset || 0), bufferView.byteLength);
|
|
}
|
|
}
|
|
@@ -1120,58 +1149,83 @@ module BABYLON.GLTF2 {
|
|
return bufferView._data;
|
|
return bufferView._data;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadAccessorAsync(context: string, accessor: ILoaderAccessor): Promise<ArrayBufferView> {
|
|
|
|
- if (accessor.sparse) {
|
|
|
|
- throw new Error(`${context}: Sparse accessors are not currently supported`);
|
|
|
|
|
|
+ private _loadIndicesAccessorAsync(context: string, accessor: _ILoaderAccessor): Promise<IndicesArray> {
|
|
|
|
+ if (accessor.type !== AccessorType.SCALAR) {
|
|
|
|
+ throw new Error(`${context}: Invalid type ${accessor.type}`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor.componentType !== AccessorComponentType.UNSIGNED_BYTE &&
|
|
|
|
+ accessor.componentType !== AccessorComponentType.UNSIGNED_SHORT &&
|
|
|
|
+ accessor.componentType !== AccessorComponentType.UNSIGNED_INT) {
|
|
|
|
+ throw new Error(`${context}: Invalid component type ${accessor.componentType}`);
|
|
}
|
|
}
|
|
|
|
|
|
if (accessor._data) {
|
|
if (accessor._data) {
|
|
- return accessor._data;
|
|
|
|
|
|
+ return accessor._data as Promise<IndicesArray>;
|
|
}
|
|
}
|
|
|
|
|
|
- const bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
- accessor._data = this._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(data => {
|
|
|
|
- const buffer = data.buffer;
|
|
|
|
- const byteOffset = data.byteOffset + (accessor.byteOffset || 0);
|
|
|
|
- const length = GLTFLoader._GetNumComponents(context, accessor.type) * accessor.count;
|
|
|
|
|
|
+ const bufferView = GLTFLoader._GetProperty(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
+ accessor._data = this._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView).then(data => {
|
|
|
|
+ return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, accessor.count);
|
|
|
|
+ });
|
|
|
|
|
|
- try {
|
|
|
|
- switch (accessor.componentType) {
|
|
|
|
- case AccessorComponentType.BYTE: {
|
|
|
|
- return new Int8Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- case AccessorComponentType.UNSIGNED_BYTE: {
|
|
|
|
- return new Uint8Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- case AccessorComponentType.SHORT: {
|
|
|
|
- return new Int16Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- case AccessorComponentType.UNSIGNED_SHORT: {
|
|
|
|
- return new Uint16Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- case AccessorComponentType.UNSIGNED_INT: {
|
|
|
|
- return new Uint32Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- case AccessorComponentType.FLOAT: {
|
|
|
|
- return new Float32Array(buffer, byteOffset, length);
|
|
|
|
- }
|
|
|
|
- default: {
|
|
|
|
- throw new Error(`${context}: Invalid accessor component type ${accessor.componentType}`);
|
|
|
|
|
|
+ return accessor._data as Promise<IndicesArray>;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private _loadFloatAccessorAsync(context: string, accessor: _ILoaderAccessor): Promise<Float32Array> {
|
|
|
|
+ // TODO: support normalized and stride
|
|
|
|
+
|
|
|
|
+ if (accessor.componentType !== AccessorComponentType.FLOAT) {
|
|
|
|
+ throw new Error(`Invalid component type ${accessor.componentType}`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor._data) {
|
|
|
|
+ return accessor._data as Promise<Float32Array>;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
|
|
|
|
+ const length = numComponents * accessor.count;
|
|
|
|
+
|
|
|
|
+ if (accessor.bufferView == undefined) {
|
|
|
|
+ accessor._data = Promise.resolve(new Float32Array(length));
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ const bufferView = GLTFLoader._GetProperty(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
+ accessor._data = this._loadBufferViewAsync(`#/bufferViews/${bufferView._index}`, bufferView).then(data => {
|
|
|
|
+ return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, length);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor.sparse) {
|
|
|
|
+ const sparse = accessor.sparse;
|
|
|
|
+ accessor._data = accessor._data.then((data: Float32Array) => {
|
|
|
|
+ const indicesBufferView = GLTFLoader._GetProperty(`${context}/sparse/indices/bufferView`, this._gltf.bufferViews, sparse.indices.bufferView);
|
|
|
|
+ const valuesBufferView = GLTFLoader._GetProperty(`${context}/sparse/values/bufferView`, this._gltf.bufferViews, sparse.values.bufferView);
|
|
|
|
+ return Promise.all([
|
|
|
|
+ this._loadBufferViewAsync(`#/bufferViews/${indicesBufferView._index}`, indicesBufferView),
|
|
|
|
+ this._loadBufferViewAsync(`#/bufferViews/${valuesBufferView._index}`, valuesBufferView)
|
|
|
|
+ ]).then(([indicesData, valuesData]) => {
|
|
|
|
+ const indices = GLTFLoader._GetTypedArray(`${context}/sparse/indices`, sparse.indices.componentType, indicesData, sparse.indices.byteOffset, sparse.count) as IndicesArray;
|
|
|
|
+ const values = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, numComponents * sparse.count) as Float32Array;
|
|
|
|
+
|
|
|
|
+ let valuesIndex = 0;
|
|
|
|
+ for (let indicesIndex = 0; indicesIndex < indices.length; indicesIndex++) {
|
|
|
|
+ let dataIndex = indices[indicesIndex] * numComponents;
|
|
|
|
+ for (let componentIndex = 0; componentIndex < numComponents; componentIndex++) {
|
|
|
|
+ data[dataIndex++] = values[valuesIndex++];
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
- }
|
|
|
|
- catch (e) {
|
|
|
|
- throw new Error(`${context}: ${e}`);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
|
|
- return accessor._data;
|
|
|
|
|
|
+ return data;
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return accessor._data as Promise<Float32Array>;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadVertexBufferViewAsync(context: string, bufferView: ILoaderBufferView, kind: string): Promise<Buffer> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadVertexBufferViewAsync(context: string, bufferView: _ILoaderBufferView, kind: string): Promise<Buffer> {
|
|
if (bufferView._babylonBuffer) {
|
|
if (bufferView._babylonBuffer) {
|
|
return bufferView._babylonBuffer;
|
|
return bufferView._babylonBuffer;
|
|
}
|
|
}
|
|
@@ -1183,21 +1237,24 @@ module BABYLON.GLTF2 {
|
|
return bufferView._babylonBuffer;
|
|
return bufferView._babylonBuffer;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadVertexAccessorAsync(context: string, accessor: ILoaderAccessor, kind: string): Promise<VertexBuffer> {
|
|
|
|
- if (accessor.sparse) {
|
|
|
|
- throw new Error(`${context}: Sparse accessors are not currently supported`);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ private _loadVertexAccessorAsync(context: string, accessor: _ILoaderAccessor, kind: string): Promise<VertexBuffer> {
|
|
if (accessor._babylonVertexBuffer) {
|
|
if (accessor._babylonVertexBuffer) {
|
|
return accessor._babylonVertexBuffer;
|
|
return accessor._babylonVertexBuffer;
|
|
}
|
|
}
|
|
|
|
|
|
- const bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
- accessor._babylonVertexBuffer = this._loadVertexBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView, kind).then(buffer => {
|
|
|
|
- const size = GLTFLoader._GetNumComponents(context, accessor.type);
|
|
|
|
- return new VertexBuffer(this._babylonScene.getEngine(), buffer, kind, false, false, bufferView.byteStride,
|
|
|
|
- false, accessor.byteOffset, size, accessor.componentType, accessor.normalized, true);
|
|
|
|
- });
|
|
|
|
|
|
+ if (accessor.sparse) {
|
|
|
|
+ accessor._babylonVertexBuffer = this._loadFloatAccessorAsync(context, accessor).then(data => {
|
|
|
|
+ return new VertexBuffer(this._babylonScene.getEngine(), data, kind, false);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ const bufferView = GLTFLoader._GetProperty(context + "/bufferView", this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
+ accessor._babylonVertexBuffer = this._loadVertexBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView, kind).then(buffer => {
|
|
|
|
+ const size = GLTFLoader._GetNumComponents(context, accessor.type);
|
|
|
|
+ return new VertexBuffer(this._babylonScene.getEngine(), buffer, kind, false, false, bufferView.byteStride,
|
|
|
|
+ false, accessor.byteOffset, size, accessor.componentType, accessor.normalized, true);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
return accessor._babylonVertexBuffer;
|
|
return accessor._babylonVertexBuffer;
|
|
}
|
|
}
|
|
@@ -1215,7 +1272,7 @@ module BABYLON.GLTF2 {
|
|
return babylonMaterial;
|
|
return babylonMaterial;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, material: ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void> {
|
|
|
|
|
|
+ private _loadMaterialMetallicRoughnessPropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void> {
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
// Ensure metallic workflow
|
|
// Ensure metallic workflow
|
|
@@ -1257,10 +1314,8 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadMaterialAsync(context: string, material: ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Promise<void> {
|
|
const promise = GLTFLoaderExtension._LoadMaterialAsync(this, context, material, babylonMesh, babylonDrawMode, assign);
|
|
const promise = GLTFLoaderExtension._LoadMaterialAsync(this, context, material, babylonMesh, babylonDrawMode, assign);
|
|
if (promise) {
|
|
if (promise) {
|
|
return promise;
|
|
return promise;
|
|
@@ -1294,20 +1349,16 @@ module BABYLON.GLTF2 {
|
|
return babylonData.loaded;
|
|
return babylonData.loaded;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _createMaterial<T extends Material>(type: MaterialConstructor<T>, name: string, drawMode: number): T {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _createMaterial<T extends Material>(type: _MaterialConstructor<T>, name: string, drawMode: number): T {
|
|
const babylonMaterial = new type(name, this._babylonScene);
|
|
const babylonMaterial = new type(name, this._babylonScene);
|
|
babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
|
|
babylonMaterial.sideOrientation = this._babylonScene.useRightHandedSystem ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
|
|
babylonMaterial.fillMode = drawMode;
|
|
babylonMaterial.fillMode = drawMode;
|
|
return babylonMaterial;
|
|
return babylonMaterial;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadMaterialBasePropertiesAsync(context: string, material: ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void> {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadMaterialBasePropertiesAsync(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): Promise<void> {
|
|
const promises = new Array<Promise<void>>();
|
|
const promises = new Array<Promise<void>>();
|
|
|
|
|
|
babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
|
|
babylonMaterial.emissiveColor = material.emissiveFactor ? Color3.FromArray(material.emissiveFactor) : new Color3(0, 0, 0);
|
|
@@ -1348,10 +1399,8 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
- public _loadMaterialAlphaProperties(context: string, material: ILoaderMaterial, babylonMaterial: PBRMaterial): void {
|
|
|
|
|
|
+ /** @hidden */
|
|
|
|
+ public _loadMaterialAlphaProperties(context: string, material: _ILoaderMaterial, babylonMaterial: PBRMaterial): void {
|
|
const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE;
|
|
const alphaMode = material.alphaMode || MaterialAlphaMode.OPAQUE;
|
|
switch (alphaMode) {
|
|
switch (alphaMode) {
|
|
case MaterialAlphaMode.OPAQUE: {
|
|
case MaterialAlphaMode.OPAQUE: {
|
|
@@ -1380,9 +1429,7 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
public _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void> {
|
|
public _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Promise<void> {
|
|
const texture = GLTFLoader._GetProperty(`${context}/index`, this._gltf.textures, textureInfo.index);
|
|
const texture = GLTFLoader._GetProperty(`${context}/index`, this._gltf.textures, textureInfo.index);
|
|
context = `#/textures/${textureInfo.index}`;
|
|
context = `#/textures/${textureInfo.index}`;
|
|
@@ -1420,7 +1467,7 @@ module BABYLON.GLTF2 {
|
|
return Promise.all(promises).then(() => {});
|
|
return Promise.all(promises).then(() => {});
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadSampler(context: string, sampler: ILoaderSampler): ILoaderSamplerData {
|
|
|
|
|
|
+ private _loadSampler(context: string, sampler: _ILoaderSampler): _ILoaderSamplerData {
|
|
if (!sampler._data) {
|
|
if (!sampler._data) {
|
|
sampler._data = {
|
|
sampler._data = {
|
|
noMipMaps: (sampler.minFilter === TextureMinFilter.NEAREST || sampler.minFilter === TextureMinFilter.LINEAR),
|
|
noMipMaps: (sampler.minFilter === TextureMinFilter.NEAREST || sampler.minFilter === TextureMinFilter.LINEAR),
|
|
@@ -1433,7 +1480,7 @@ module BABYLON.GLTF2 {
|
|
return sampler._data;
|
|
return sampler._data;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadImageAsync(context: string, image: ILoaderImage): Promise<string> {
|
|
|
|
|
|
+ private _loadImageAsync(context: string, image: _ILoaderImage): Promise<string> {
|
|
if (image._objectURL) {
|
|
if (image._objectURL) {
|
|
return image._objectURL;
|
|
return image._objectURL;
|
|
}
|
|
}
|
|
@@ -1454,9 +1501,7 @@ module BABYLON.GLTF2 {
|
|
return image._objectURL;
|
|
return image._objectURL;
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
public _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView> {
|
|
public _loadUriAsync(context: string, uri: string): Promise<ArrayBufferView> {
|
|
const promise = GLTFLoaderExtension._LoadUriAsync(this, context, uri);
|
|
const promise = GLTFLoaderExtension._LoadUriAsync(this, context, uri);
|
|
if (promise) {
|
|
if (promise) {
|
|
@@ -1521,9 +1566,7 @@ module BABYLON.GLTF2 {
|
|
this._progressCallback(new SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
|
|
this._progressCallback(new SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
public static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T {
|
|
public static _GetProperty<T>(context: string, array: ArrayLike<T> | undefined, index: number | undefined): T {
|
|
if (!array || index == undefined || !array[index]) {
|
|
if (!array || index == undefined || !array[index]) {
|
|
throw new Error(`${context}: Failed to find index (${index})`);
|
|
throw new Error(`${context}: Failed to find index (${index})`);
|
|
@@ -1583,6 +1626,26 @@ module BABYLON.GLTF2 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private static _GetTypedArray(context: string, componentType: AccessorComponentType, bufferView: ArrayBufferView, byteOffset: number | undefined, length: number): ArrayBufferView {
|
|
|
|
+ const buffer = bufferView.buffer;
|
|
|
|
+ byteOffset = bufferView.byteOffset + (byteOffset || 0);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ switch (componentType) {
|
|
|
|
+ case AccessorComponentType.BYTE: return new Int8Array(buffer, byteOffset, length);
|
|
|
|
+ case AccessorComponentType.UNSIGNED_BYTE: return new Uint8Array(buffer, byteOffset, length);
|
|
|
|
+ case AccessorComponentType.SHORT: return new Int16Array(buffer, byteOffset, length);
|
|
|
|
+ case AccessorComponentType.UNSIGNED_SHORT: return new Uint16Array(buffer, byteOffset, length);
|
|
|
|
+ case AccessorComponentType.UNSIGNED_INT: return new Uint32Array(buffer, byteOffset, length);
|
|
|
|
+ case AccessorComponentType.FLOAT: return new Float32Array(buffer, byteOffset, length);
|
|
|
|
+ default: throw new Error(`Invalid component type ${componentType}`);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch (e) {
|
|
|
|
+ throw new Error(`${context}: ${e}`);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
private static _GetNumComponents(context: string, type: string): number {
|
|
private static _GetNumComponents(context: string, type: string): number {
|
|
switch (type) {
|
|
switch (type) {
|
|
case "SCALAR": return 1;
|
|
case "SCALAR": return 1;
|
|
@@ -1694,11 +1757,10 @@ module BABYLON.GLTF2 {
|
|
this.onMeshLoadedObservable.clear();
|
|
this.onMeshLoadedObservable.clear();
|
|
this.onTextureLoadedObservable.clear();
|
|
this.onTextureLoadedObservable.clear();
|
|
this.onMaterialLoadedObservable.clear();
|
|
this.onMaterialLoadedObservable.clear();
|
|
|
|
+ this.onCameraLoadedObservable.clear();
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @ignore
|
|
|
|
- */
|
|
|
|
|
|
+ /** @hidden */
|
|
public _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>) {
|
|
public _applyExtensions<T>(actionAsync: (extension: GLTFLoaderExtension) => Nullable<Promise<T>>) {
|
|
for (const name of GLTFLoader._Names) {
|
|
for (const name of GLTFLoader._Names) {
|
|
const extension = this._extensions[name];
|
|
const extension = this._extensions[name];
|