Bläddra i källkod

Add support for cameras to glTF loader

Gary Hsu 7 år sedan
förälder
incheckning
27b872f064

+ 2 - 2
dist/babylon.glTF2Interface.d.ts

@@ -144,9 +144,9 @@ declare module BABYLON.GLTF2 {
         znear: number;
     }
     interface ICameraPerspective extends IProperty {
-        aspectRatio: number;
+        aspectRatio?: number;
         yfov: number;
-        zfar: number;
+        zfar?: number;
         znear: number;
     }
     interface ICamera extends IChildRootProperty {

+ 1 - 0
dist/preview release/what's new.md

@@ -116,6 +116,7 @@
 - New serialize and parse functions for effect layers (Highlight and Glow layers) ([julien-moreau](https://github.com/julien-moreau))
 - Added alphaCutOff support for StandardMaterial ([deltakosh](https://github.com/deltakosh))
 - Add support for sparse accessors to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
+- Add support for cameras to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
 
 ## Bug fixes
 

+ 3 - 2
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -885,7 +885,7 @@ module BABYLON.GLTF1 {
 
             if (camera) {
                 if (camera.type === "orthographic") {
-                    var orthoCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene);
+                    var orthoCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene, false);
 
                     orthoCamera.name = node.name || "";
                     orthoCamera.mode = Camera.ORTHOGRAPHIC_CAMERA;
@@ -895,7 +895,7 @@ module BABYLON.GLTF1 {
                 }
                 else if (camera.type === "perspective") {
                     var perspectiveCamera: IGLTFCameraPerspective = (<any>camera)[camera.type];
-                    var persCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene);
+                    var persCamera = new FreeCamera(node.camera, Vector3.Zero(), gltfRuntime.scene, false);
 
                     persCamera.name = node.name || "";
                     persCamera.attachControl(<HTMLElement>gltfRuntime.scene.getEngine().getRenderingCanvas());
@@ -1573,6 +1573,7 @@ module BABYLON.GLTF1 {
         public onMeshLoadedObservable = new Observable<AbstractMesh>();
         public onTextureLoadedObservable = new Observable<BaseTexture>();
         public onMaterialLoadedObservable = new Observable<Material>();
+        public onCameraLoadedObservable = new Observable<Camera>();
         public onCompleteObservable = new Observable<IGLTFLoader>();
         public onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
 

+ 50 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -96,6 +96,11 @@ module BABYLON.GLTF2 {
         public readonly onMaterialLoadedObservable = new Observable<Material>();
 
         /**
+         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
+         */
+        public readonly onCameraLoadedObservable = new Observable<Camera>();
+
+        /**
          * 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.
@@ -506,6 +511,11 @@ module BABYLON.GLTF2 {
                 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) {
                 for (const index of node.children) {
                     const childNode = GLTFLoader._GetProperty(`${context}/children/${index}`, this._gltf.nodes, index);
@@ -845,6 +855,45 @@ module BABYLON.GLTF2 {
                     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> {
             const animations = this._gltf.animations;
             if (!animations) {
@@ -1705,6 +1754,7 @@ module BABYLON.GLTF2 {
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
+            this.onCameraLoadedObservable.clear();
         }
 
         /** @hidden */

+ 1 - 1
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -90,7 +90,7 @@ module BABYLON.GLTF2 {
 }
 
 /**
- * Defines the module of the glTF loader extensions.
+ * Defines the module of the glTF 2.0 loader extensions.
  */
 module BABYLON.GLTF2.Extensions {
 }

+ 32 - 1
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -131,6 +131,11 @@ module BABYLON {
         onMaterialLoadedObservable: Observable<Material>;
 
         /**
+         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
+         */
+        onCameraLoadedObservable: Observable<Camera>;
+
+        /**
          * 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.
@@ -295,6 +300,23 @@ module BABYLON {
         }
 
         /**
+         * Observable raised when the loader creates a camera after parsing the glTF properties of the camera.
+         */
+        public readonly onCameraLoadedObservable = new Observable<Camera>();
+
+        private _onCameraLoadedObserver: Nullable<Observer<Camera>>;
+
+        /**
+         * Callback raised when the loader creates a camera after parsing the glTF properties of the camera.
+         */
+        public set onCameraLoaded(callback: (camera: Camera) => void) {
+            if (this._onCameraLoadedObserver) {
+                this.onCameraLoadedObservable.remove(this._onCameraLoadedObserver);
+            }
+            this._onCameraLoadedObserver = this.onCameraLoadedObservable.add(callback);
+        }
+
+        /**
          * 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.
@@ -396,6 +418,9 @@ module BABYLON {
             this.onMeshLoadedObservable.clear();
             this.onTextureLoadedObservable.clear();
             this.onMaterialLoadedObservable.clear();
+            this.onCameraLoadedObservable.clear();
+            this.onCompleteObservable.clear();
+            this.onExtensionLoadedObservable.clear();
 
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
@@ -538,12 +563,18 @@ module BABYLON {
             loader.onMeshLoadedObservable.add(mesh => this.onMeshLoadedObservable.notifyObservers(mesh));
             loader.onTextureLoadedObservable.add(texture => this.onTextureLoadedObservable.notifyObservers(texture));
             loader.onMaterialLoadedObservable.add(material => this.onMaterialLoadedObservable.notifyObservers(material));
-            loader.onExtensionLoadedObservable.add(extension => this.onExtensionLoadedObservable.notifyObservers(extension));
+            loader.onCameraLoadedObservable.add(camera => this.onCameraLoadedObservable.notifyObservers(camera));
+
+            loader.onExtensionLoadedObservable.add(extension => {
+                this.onExtensionLoadedObservable.notifyObservers(extension);
+                this.onExtensionLoadedObservable.clear();
+            });
 
             loader.onCompleteObservable.add(() => {
                 this.onMeshLoadedObservable.clear();
                 this.onTextureLoadedObservable.clear();
                 this.onMaterialLoadedObservable.clear();
+                this.onCameraLoadedObservable.clear();
 
                 this.onCompleteObservable.notifyObservers(this);
                 this.onCompleteObservable.clear();

+ 1 - 6
sandbox/index.js

@@ -92,11 +92,6 @@ if (BABYLON.Engine.isSupported()) {
         // Fix for IE, otherwise it will change the default filter for files selection after first use
         htmlInput.value = "";
 
-        // removing glTF created camera
-        if (currentScene.activeCamera && currentPluginName === "gltf") {
-            currentScene.activeCamera.dispose();
-            currentScene.activeCamera = null;
-        }
         // Attach camera to canvas inputs
         if (!currentScene.activeCamera || currentScene.lights.length === 0) {
             currentScene.createDefaultCameraOrLight(true);
@@ -265,7 +260,7 @@ if (BABYLON.Engine.isSupported()) {
 
     window.addEventListener("keydown", function (evt) {
         // Press Esc to toggle footer
-        if (evt.keyCode === 27) {
+        if (evt.keyCode === 27 &&!enableDebugLayer) {
             if (footer.style.display === "none") {
                 footer.style.display = "block";
             }

+ 2 - 2
src/Cameras/Inputs/babylon.freeCameraMouseInput.ts

@@ -76,7 +76,7 @@ module BABYLON {
                         var offsetX = evt.clientX - this.previousPosition.x;
                         var offsetY = evt.clientY - this.previousPosition.y;
 
-                        if (this.camera.getScene().useRightHandedSystem) {
+                        if (this.camera.getScene().useRightHandedSystem === (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() >= 0)) {
                             this.camera.cameraRotation.y -= offsetX / this.angularSensibility;
                         } else {
                             this.camera.cameraRotation.y += offsetX / this.angularSensibility;
@@ -108,7 +108,7 @@ module BABYLON {
                 var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
                 var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
 
-                if (this.camera.getScene().useRightHandedSystem) {
+                if (this.camera.getScene().useRightHandedSystem === (this.camera.parent && this.camera.parent._getWorldMatrixDeterminant() >= 0)) {
                     this.camera.cameraRotation.y -= offsetX / this.angularSensibility;
                 } else {
                     this.camera.cameraRotation.y += offsetX / this.angularSensibility;

+ 5 - 8
src/Cameras/babylon.arcRotateCamera.ts

@@ -340,8 +340,8 @@
 
         private _computationVector: Vector3 = Vector3.Zero();
 
-        constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene) {
-            super(name, Vector3.Zero(), scene);
+        constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene, setActiveOnSceneIfNoneActive = true) {
+            super(name, Vector3.Zero(), scene, setActiveOnSceneIfNoneActive);
 
             this._target = Vector3.Zero();
             if (target) {
@@ -485,7 +485,7 @@
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
 
-                if (this.getScene().useRightHandedSystem) {
+                if (this.getScene().useRightHandedSystem === (this.parent && this.parent._getWorldMatrixDeterminant() >= 0)) {
                     this.alpha -= this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
                 } else {
                     this.alpha += this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
@@ -673,11 +673,8 @@
                     up = up.negate();
                 }
 
-                if (this.getScene().useRightHandedSystem) {
-                    Matrix.LookAtRHToRef(this.position, target, up, this._viewMatrix);
-                } else {
-                    Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
-                }
+                this._computeViewMatrix(this.position, target, up);
+
                 this._viewMatrix.m[12] += this.targetScreenOffset.x;
                 this._viewMatrix.m[13] += this.targetScreenOffset.y;
             }

+ 3 - 20
src/Cameras/babylon.camera.ts

@@ -166,16 +166,16 @@
 
         public _activeMeshes = new SmartArray<AbstractMesh>(256);
 
-        private _globalPosition = Vector3.Zero();
+        protected _globalPosition = Vector3.Zero();
         private _frustumPlanes: Plane[];
         private _refreshFrustumPlanes = true;
 
-        constructor(name: string, position: Vector3, scene: Scene) {
+        constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive = true) {
             super(name, scene);
 
             this.getScene().addCamera(this);
 
-            if (!this.getScene().activeCamera) {
+            if (setActiveOnSceneIfNoneActive && !this.getScene().activeCamera) {
                 this.getScene().activeCamera = this;
             }
 
@@ -462,23 +462,6 @@
 
             this._refreshFrustumPlanes = true;
 
-            if (!this.parent || !this.parent.getWorldMatrix) {
-                this._globalPosition.copyFrom(this.position);
-            } else {
-                if (!this._worldMatrix) {
-                    this._worldMatrix = Matrix.Identity();
-                }
-
-                this._computedViewMatrix.invertToRef(this._worldMatrix);
-
-                this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
-                this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
-
-                this._computedViewMatrix.invert();
-
-                this._markSyncedWithParent();
-            }
-
             if (this._cameraRigParams && this._cameraRigParams.vrPreViewMatrix) {
                 this._computedViewMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._computedViewMatrix);
             }

+ 2 - 2
src/Cameras/babylon.freeCamera.ts

@@ -106,8 +106,8 @@
         public _localDirection: Vector3;
         public _transformedDirection: Vector3;
 
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
+        constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive = true) {
+            super(name, position, scene, setActiveOnSceneIfNoneActive);
             this.inputs = new FreeCameraInputsManager(this);
             this.inputs.addKeyboard().addMouse();
         }

+ 24 - 8
src/Cameras/babylon.targetCamera.ts

@@ -27,13 +27,14 @@
         public _referencePoint = new Vector3(0, 0, 1);
         private _currentUpVector = new Vector3(0, 1, 0);
         public _transformedReferencePoint = Vector3.Zero();
-        public _lookAtTemp = Matrix.Zero();
-        public _tempMatrix = Matrix.Zero();
+
+        protected _globalCurrentTarget = Vector3.Zero();
+        protected _globalCurrentUpVector = Vector3.Zero();
 
         public _reset: () => void;
 
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
+        constructor(name: string, position: Vector3, scene: Scene, setActiveOnSceneIfNoneActive = true) {
+            super(name, position, scene, setActiveOnSceneIfNoneActive);
         }
 
         public getFrontPosition(distance: number): Vector3 {
@@ -290,13 +291,28 @@
             // Computing target and final matrix
             this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
 
-            if (this.getScene().useRightHandedSystem) {
-                Matrix.LookAtRHToRef(this.position, this._currentTarget, this._currentUpVector, this._viewMatrix);
+            this._computeViewMatrix(this.position, this._currentTarget, this._currentUpVector);
+            return this._viewMatrix;
+        }
+
+        protected _computeViewMatrix(position: Vector3, target: Vector3, up: Vector3): void {
+            if (this.parent) {
+                const parentWorldMatrix = this.parent.getWorldMatrix();
+                Vector3.TransformCoordinatesToRef(this.position, parentWorldMatrix, this._globalPosition);
+                Vector3.TransformCoordinatesToRef(target, parentWorldMatrix, this._globalCurrentTarget);
+                Vector3.TransformNormalToRef(up, parentWorldMatrix, this._globalCurrentUpVector);
+                this._markSyncedWithParent();
             } else {
-                Matrix.LookAtLHToRef(this.position, this._currentTarget, this._currentUpVector, this._viewMatrix);
+                this._globalPosition.copyFrom(this.position);
+                this._globalCurrentTarget.copyFrom(target);
+                this._globalCurrentUpVector.copyFrom(up);
             }
 
-            return this._viewMatrix;
+            if (this.getScene().useRightHandedSystem) {
+                Matrix.LookAtRHToRef(this._globalPosition, this._globalCurrentTarget, this._globalCurrentUpVector, this._viewMatrix);
+            } else {
+                Matrix.LookAtLHToRef(this._globalPosition, this._globalCurrentTarget, this._globalCurrentUpVector, this._viewMatrix);
+            }
         }
 
         /**

+ 1 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -983,7 +983,7 @@
         }
 
         /** @hidden */
-        protected _getWorldMatrixDeterminant(): number {
+        public _getWorldMatrixDeterminant(): number {
             if (this._masterMesh) {
                 return this._masterMesh._getWorldMatrixDeterminant();
             }

+ 2 - 4
src/Mesh/babylon.transformNode.ts

@@ -157,10 +157,8 @@ module BABYLON {
             return this._worldMatrix;
         }
 
-        /**
-         * Returns the latest update of the World matrix determinant.
-         */
-        protected _getWorldMatrixDeterminant(): number {
+        /** @hidden */
+        public _getWorldMatrixDeterminant(): number {
             return this._worldMatrixDeterminant;
         }
 

+ 5 - 0
src/babylon.node.ts

@@ -264,6 +264,11 @@
             return Matrix.Identity();
         }
 
+        /** @hidden */
+        public _getWorldMatrixDeterminant(): number {
+            return 1;
+        }
+
         // override it in derived class if you add new variables to the cache
         // and call the parent class method
         /** @hidden */