瀏覽代碼

LOD and instances are now working

David Catuhe 10 年之前
父節點
當前提交
e8c6dcbd09

+ 23 - 5
Babylon/Audio/babylon.audioengine.js

@@ -1,23 +1,41 @@
 var BABYLON;
 (function (BABYLON) {
-    // We're mainly based on the logic defined into the FreeCamera code
     var AudioEngine = (function () {
         function AudioEngine() {
             this.audioContext = null;
-            this.canUseWebAudio = true;
+            this.canUseWebAudio = false;
             try  {
                 if (typeof AudioContext !== 'undefined') {
                     this.audioContext = new AudioContext();
+                    this.canUseWebAudio = true;
                 } else if (typeof webkitAudioContext !== 'undefined') {
                     this.audioContext = new webkitAudioContext();
-                } else {
-                    this.canUseWebAudio = false;
+                    this.canUseWebAudio = true;
                 }
             } catch (e) {
-                // Web
                 this.canUseWebAudio = false;
             }
+
+            // create a global volume gain node
+            if (this.canUseWebAudio) {
+                this.masterGain = this.audioContext.createGain();
+                this.masterGain.gain.value = 1;
+                this.masterGain.connect(this.audioContext.destination);
+            }
         }
+        AudioEngine.prototype.getGlobalVolume = function () {
+            if (this.canUseWebAudio) {
+                return this.masterGain.gain.value;
+            } else {
+                return -1;
+            }
+        };
+
+        AudioEngine.prototype.setGlobalVolume = function (newVolume) {
+            if (this.canUseWebAudio) {
+                this.masterGain.gain.value = newVolume;
+            }
+        };
         return AudioEngine;
     })();
     BABYLON.AudioEngine = AudioEngine;

+ 30 - 6
Babylon/Audio/babylon.sound.js

@@ -1,15 +1,17 @@
 var BABYLON;
 (function (BABYLON) {
     var Sound = (function () {
-        function Sound(url, audioEngine, readyToPlayCallback, distanceMax, autoplay, loop) {
+        function Sound(url, engine, readyToPlayCallback, distanceMax, autoplay, loop) {
             var _this = this;
             this.distanceMax = 10;
             this.autoplay = false;
             this.loop = false;
             this._position = BABYLON.Vector3.Zero();
+            this._orientation = BABYLON.Vector3.Zero();
             this._isLoaded = false;
             this._isReadyToPlay = false;
-            this._audioEngine = audioEngine;
+            this._audioEngine = engine.getAudioEngine();
+            ;
             this._readyToPlayCallback = readyToPlayCallback;
             if (distanceMax)
                 this.distanceMax = distanceMax;
@@ -17,26 +19,35 @@
                 this.autoplay = autoplay;
             if (loop)
                 this.loop = loop;
-            if (audioEngine.canUseWebAudio) {
+            if (this._audioEngine.canUseWebAudio) {
                 BABYLON.Tools.LoadFile(url, function (data) {
                     _this._soundLoaded(data);
                 }, null, null, true);
             }
         }
         Sound.prototype.setPosition = function (newPosition) {
+            this._position = newPosition;
+
             if (this._isReadyToPlay) {
-                this._position = newPosition;
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
 
+        Sound.prototype.setOrientiation = function (newOrientation) {
+            this._orientation = newOrientation;
+
+            if (this._isReadyToPlay) {
+                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            }
+        };
+
         Sound.prototype.play = function () {
             if (this._isReadyToPlay) {
                 this._soundSource = this._audioEngine.audioContext.createBufferSource();
                 this._soundSource.buffer = this._audioBuffer;
                 this._soundPanner = this._audioEngine.audioContext.createPanner();
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
-                this._soundPanner.connect(this._audioEngine.audioContext.destination);
+                this._soundPanner.connect(this._audioEngine.masterGain);
                 this._soundSource.connect(this._soundPanner);
                 this._soundSource.loop = this.loop;
                 this._soundSource.start(0);
@@ -49,6 +60,17 @@
         Sound.prototype.pause = function () {
         };
 
+        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+            var _this = this;
+            meshToConnectTo.registerAfterWorldMatrixUpdate(function (connectedMesh) {
+                return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh);
+            });
+        };
+
+        Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
+            this.setPosition(connectedMesh.position);
+        };
+
         Sound.prototype._soundLoaded = function (audioData) {
             var _this = this;
             this._isLoaded = true;
@@ -59,7 +81,9 @@
                     _this.play();
                 if (_this._readyToPlayCallback)
                     _this._readyToPlayCallback();
-            }, null);
+            }, function (error) {
+                BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
+            });
         };
         return Sound;
     })();

+ 2 - 2
Babylon/Loading/babylon.sceneLoader.js

@@ -64,14 +64,14 @@
                     try  {
                         if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
                             if (onerror) {
-                                onerror(scene);
+                                onerror(scene, 'unable to load the scene');
                             }
 
                             return;
                         }
                     } catch (e) {
                         if (onerror) {
-                            onerror(scene);
+                            onerror(scene, e);
                         }
 
                         return;

+ 12 - 2
Babylon/Mesh/babylon.InstancedMesh.js

@@ -107,11 +107,21 @@ var BABYLON;
         };
 
         InstancedMesh.prototype._preActivate = function () {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         };
 
         InstancedMesh.prototype._activate = function (renderId) {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        };
+
+        InstancedMesh.prototype.getLOD = function (camera) {
+            this._currentLOD = this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD;
         };
 
         InstancedMesh.prototype._syncSubMeshes = function () {

+ 13 - 2
Babylon/Mesh/babylon.InstancedMesh.ts

@@ -1,6 +1,7 @@
 module BABYLON {
     export class InstancedMesh extends AbstractMesh {
         private _sourceMesh: Mesh;
+        private _currentLOD: Mesh;
 
         constructor(name: string, source: Mesh) {
             super(name, source.getScene());
@@ -78,11 +79,21 @@
         }
 
         public _preActivate(): void {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         }
 
         public _activate(renderId: number): void {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        }
+
+        public getLOD(camera: Camera): AbstractMesh {
+            this._currentLOD = <Mesh>this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD
         }
 
         public _syncSubMeshes(): void {

+ 36 - 1
Babylon/Mesh/babylon.abstractMesh.js

@@ -61,6 +61,7 @@ var BABYLON;
             this._isDisposed = false;
             this._renderId = 0;
             this._intersectionsInProgress = new Array();
+            this._onAfterWorldMatrixUpdate = new Array();
 
             scene.meshes.push(this);
         }
@@ -134,6 +135,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getBoundingInfo = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -148,6 +153,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getWorldMatrix = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -308,6 +317,10 @@ var BABYLON;
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        };
+
+        AbstractMesh.prototype._updateSubMeshesBoundingInfo = function (matrix) {
             if (!this.subMeshes) {
                 return;
             }
@@ -315,7 +328,7 @@ var BABYLON;
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         };
 
@@ -404,9 +417,29 @@ var BABYLON;
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
 
+            for (var callbackIndex = 0; callbackIndex < this._onAfterWorldMatrixUpdate.length; callbackIndex++) {
+                this._onAfterWorldMatrixUpdate[callbackIndex](this);
+            }
+
             return this._worldMatrix;
         };
 
+        /**
+        * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
+        * @param func: callback function to add
+        */
+        AbstractMesh.prototype.registerAfterWorldMatrixUpdate = function (func) {
+            this._onAfterWorldMatrixUpdate.push(func);
+        };
+
+        AbstractMesh.prototype.unregisterAfterWorldMatrixUpdate = function (func) {
+            var index = this._onAfterWorldMatrixUpdate.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterWorldMatrixUpdate.splice(index, 1);
+            }
+        };
+
         AbstractMesh.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
 
@@ -825,6 +858,8 @@ var BABYLON;
                 }
             }
 
+            this._onAfterWorldMatrixUpdate = [];
+
             this._isDisposed = true;
 
             // Callback

+ 14 - 1
Babylon/Mesh/babylon.abstractMesh.ts

@@ -87,6 +87,7 @@
         private _collisionsScalingMatrix = BABYLON.Matrix.Zero();
         public _positions: Vector3[];
         private _isDirty = false;
+        public _masterMesh: AbstractMesh;
 
         public _boundingInfo: BoundingInfo;
         private _pivotMatrix = BABYLON.Matrix.Identity();
@@ -131,6 +132,10 @@
         }
 
         public getBoundingInfo(): BoundingInfo {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -145,6 +150,10 @@
         }
 
         public getWorldMatrix(): Matrix {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -300,6 +309,10 @@
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        }
+
+        public _updateSubMeshesBoundingInfo(matrix: Matrix): void {
             if (!this.subMeshes) {
                 return;
             }
@@ -307,7 +320,7 @@
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         }
 

+ 24 - 28
Babylon/Mesh/babylon.mesh.js

@@ -31,7 +31,15 @@ var BABYLON;
             this._batchCache = new _InstancesBatch();
             this._instancesBufferSize = 32 * 16 * 4;
         }
-        // Methods
+        Object.defineProperty(Mesh.prototype, "hasLODLevels", {
+            // Methods
+            get: function () {
+                return this._LODLevels.length > 0;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Mesh.prototype._sortLODLevels = function () {
             this._LODLevels.sort(function (a, b) {
                 if (a.distance < b.distance) {
@@ -50,7 +58,7 @@ var BABYLON;
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -59,37 +67,25 @@ var BABYLON;
         };
 
         Mesh.prototype.removeLODLevel = function (mesh) {
-            if (mesh && !mesh._attachedLODLevel) {
-                return this;
-            }
-
-            var index;
-
-            if (mesh) {
-                index = this._LODLevels.indexOf(mesh._attachedLODLevel);
-                mesh._attachedLODLevel = null;
-
-                this._LODLevels.splice(index, 1);
-
-                this._sortLODLevels();
-            } else {
-                for (index = 0; index < this._LODLevels.length; index++) {
-                    if (this._LODLevels[index].mesh === null) {
-                        this._LODLevels.splice(index, 1);
-                        break;
+            for (var index = 0; index < this._LODLevels.length; index++) {
+                if (this._LODLevels[index].mesh === mesh) {
+                    this._LODLevels.splice(index, 1);
+                    if (mesh) {
+                        mesh._masterMesh = null;
                     }
                 }
             }
 
+            this._sortLODLevels();
             return this;
         };
 
-        Mesh.prototype.getLOD = function (camera) {
+        Mesh.prototype.getLOD = function (camera, boundingSphere) {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
             }
 
-            var distanceToCamera = this.getBoundingInfo().boundingSphere.centerWorld.subtract(camera.position).length();
+            var distanceToCamera = (boundingSphere ? boundingSphere : this.getBoundingInfo().boundingSphere).centerWorld.subtract(camera.position).length();
 
             if (this._LODLevels[this._LODLevels.length - 1].distance > distanceToCamera) {
                 return this;
@@ -100,7 +96,8 @@ var BABYLON;
 
                 if (level.distance < distanceToCamera) {
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -177,7 +174,7 @@ var BABYLON;
 
         Object.defineProperty(Mesh.prototype, "isBlocked", {
             get: function () {
-                return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+                return this._masterMesh !== null && this._masterMesh !== undefined;
             },
             enumerable: true,
             configurable: true
@@ -441,7 +438,8 @@ var BABYLON;
         };
 
         Mesh.prototype._renderWithInstances = function (subMesh, fillMode, batch, effect, engine) {
-            var matricesCount = this.instances.length + 1;
+            var visibleInstances = batch.visibleInstances[subMesh._id];
+            var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
 
             while (this._instancesBufferSize < bufferSize) {
@@ -467,8 +465,6 @@ var BABYLON;
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
-
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
                     var instance = visibleInstances[instanceIndex];
@@ -512,7 +508,7 @@ var BABYLON;
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             // Material
             var effectiveMaterial = subMesh.getMaterial();

+ 20 - 26
Babylon/Mesh/babylon.mesh.ts

@@ -27,13 +27,16 @@
         private _instancesBufferSize = 32 * 16 * 4; // let's start with a maximum of 32 instances
         public _shouldGenerateFlatShading: boolean;
         private _preActivateId: number;
-        private _attachedLODLevel: BABYLON.Internals.MeshLODLevel;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
         }
 
         // Methods
+        public get hasLODLevels(): boolean {
+            return this._LODLevels.length > 0;
+        }
+
         private _sortLODLevels(): void {
             this._LODLevels.sort((a, b) => {
                 if (a.distance < b.distance) {
@@ -52,7 +55,7 @@
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -61,37 +64,26 @@
         }
 
         public removeLODLevel(mesh: Mesh): Mesh {
-            if (mesh && !mesh._attachedLODLevel) {
-                return this;
-            }
-
-            var index;
-
-            if (mesh) {
-                index = this._LODLevels.indexOf(mesh._attachedLODLevel);
-                mesh._attachedLODLevel = null;
 
-                this._LODLevels.splice(index, 1);
-
-                this._sortLODLevels();
-            } else {
-                for (index = 0; index < this._LODLevels.length; index++) {
-                    if (this._LODLevels[index].mesh === null) {
-                        this._LODLevels.splice(index, 1);
-                        break;
+            for (var index = 0; index < this._LODLevels.length; index++) {
+                if (this._LODLevels[index].mesh === mesh) {
+                    this._LODLevels.splice(index, 1);
+                    if (mesh) {
+                        mesh._masterMesh = null;
                     }
                 }
             }
 
+            this._sortLODLevels();
             return this;
         }
 
-        public getLOD(camera: Camera): AbstractMesh {
+        public getLOD(camera: Camera, boundingSphere?: BoundingSphere): AbstractMesh {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
             }
 
-            var distanceToCamera = this.getBoundingInfo().boundingSphere.centerWorld.subtract(camera.position).length();
+            var distanceToCamera = (boundingSphere ? boundingSphere : this.getBoundingInfo().boundingSphere).centerWorld.subtract(camera.position).length();
 
             if (this._LODLevels[this._LODLevels.length - 1].distance > distanceToCamera) {
                 return this;
@@ -101,8 +93,10 @@
                 var level = this._LODLevels[index];
 
                 if (level.distance < distanceToCamera) {
+
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -174,7 +168,7 @@
         }
 
         public get isBlocked(): boolean {
-            return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+            return this._masterMesh !== null && this._masterMesh !== undefined;
         }
 
         public isReady(): boolean {
@@ -442,7 +436,8 @@
         }
 
         public _renderWithInstances(subMesh: SubMesh, fillMode: number, batch: _InstancesBatch, effect: Effect, engine: Engine): void {
-            var matricesCount = this.instances.length + 1;
+            var visibleInstances = batch.visibleInstances[subMesh._id];
+            var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
 
             while (this._instancesBufferSize < bufferSize) {
@@ -468,7 +463,6 @@
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
 
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
@@ -513,7 +507,7 @@
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             // Material
             var effectiveMaterial = subMesh.getMaterial();

+ 15 - 9
Babylon/babylon.scene.js

@@ -727,18 +727,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
+                // Switch to current LOD
+                var meshLOD = mesh.getLOD(this.activeCamera);
+
+                if (!meshLOD) {
+                    continue;
+                }
+
+                mesh._preActivate();
+
                 if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
 
-                    this._activeMesh(mesh);
+                    this._activeMesh(meshLOD);
                 }
             }
 
@@ -772,27 +780,25 @@
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }
 
-            var activeMesh = mesh.getLOD(this.activeCamera);
-
-            if (activeMesh && activeMesh.subMeshes) {
+            if (mesh && mesh.subMeshes) {
                 // Submeshes Octrees
                 var len;
                 var subMeshes;
 
-                if (activeMesh._submeshesOctree && activeMesh.useOctreeForRenderingSelection) {
-                    var intersections = activeMesh._submeshesOctree.select(this._frustumPlanes);
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
 
                     len = intersections.length;
                     subMeshes = intersections.data;
                 } else {
-                    subMeshes = activeMesh.subMeshes;
+                    subMeshes = mesh.subMeshes;
                     len = subMeshes.length;
                 }
 
                 for (var subIndex = 0; subIndex < len; subIndex++) {
                     var subMesh = subMeshes[subIndex];
 
-                    this._evaluateSubMesh(subMesh, activeMesh);
+                    this._evaluateSubMesh(subMesh, mesh);
                 }
             }
         };

+ 15 - 9
Babylon/babylon.scene.ts

@@ -803,18 +803,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([ActionManager.OnIntersectionEnterTrigger, ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
+                // Switch to current LOD
+                var meshLOD = mesh.getLOD(this.activeCamera);
+
+                if (!meshLOD) {
+                    continue;
+                }
+
+                mesh._preActivate();
+
                 if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
 
-                    this._activeMesh(mesh);
+                    this._activeMesh(meshLOD);
                 }
             }
 
@@ -848,27 +856,25 @@
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }            
 
-            var activeMesh = mesh.getLOD(this.activeCamera);
-
-            if (activeMesh && activeMesh.subMeshes) {
+            if (mesh && mesh.subMeshes) {
                 // Submeshes Octrees
                 var len: number;
                 var subMeshes: SubMesh[];
 
-                if (activeMesh._submeshesOctree && activeMesh.useOctreeForRenderingSelection) {
-                    var intersections = activeMesh._submeshesOctree.select(this._frustumPlanes);
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
 
                     len = intersections.length;
                     subMeshes = intersections.data;
                 } else {
-                    subMeshes = activeMesh.subMeshes;
+                    subMeshes = mesh.subMeshes;
                     len = subMeshes.length;
                 }
 
                 for (var subIndex = 0; subIndex < len; subIndex++) {
                     var subMesh = subMeshes[subIndex];
 
-                    this._evaluateSubMesh(subMesh, activeMesh);
+                    this._evaluateSubMesh(subMesh, mesh);
                 }
             }
         }

+ 151 - 57
babylon.2.0-alpha.debug.js

@@ -3791,6 +3791,8 @@ var BABYLON;
             document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
+
+            this._audioEngine = new BABYLON.AudioEngine();
         }
         Object.defineProperty(Engine, "ALPHA_DISABLE", {
             get: function () {
@@ -3856,6 +3858,10 @@ var BABYLON;
             configurable: true
         });
 
+        Engine.prototype.getAudioEngine = function () {
+            return this._audioEngine;
+        };
+
         Engine.prototype.getAspectRatio = function (camera) {
             var viewport = camera.viewport;
             return (this.getRenderWidth() * viewport.width) / (this.getRenderHeight() * viewport.height);
@@ -8921,18 +8927,26 @@ var BABYLON;
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
+               
+                var meshLOD = mesh.getLOD(this.activeCamera);
+
+                if (!meshLOD) {
+                    continue;
+                }
+
+                mesh._preActivate();
+
                 if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
 
-                    this._activeMesh(mesh);
+                    this._activeMesh(meshLOD);
                 }
             }
 
@@ -8966,27 +8980,25 @@ var BABYLON;
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }
 
-            var activeMesh = mesh.getLOD(this.activeCamera);
-
-            if (activeMesh && activeMesh.subMeshes) {
+            if (mesh && mesh.subMeshes) {
                
                 var len;
                 var subMeshes;
 
-                if (activeMesh._submeshesOctree && activeMesh.useOctreeForRenderingSelection) {
-                    var intersections = activeMesh._submeshesOctree.select(this._frustumPlanes);
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
 
                     len = intersections.length;
                     subMeshes = intersections.data;
                 } else {
-                    subMeshes = activeMesh.subMeshes;
+                    subMeshes = mesh.subMeshes;
                     len = subMeshes.length;
                 }
 
                 for (var subIndex = 0; subIndex < len; subIndex++) {
                     var subMesh = subMeshes[subIndex];
 
-                    this._evaluateSubMesh(subMesh, activeMesh);
+                    this._evaluateSubMesh(subMesh, mesh);
                 }
             }
         };
@@ -9284,6 +9296,9 @@ var BABYLON;
             this._checkIntersections();
 
            
+            this._updateAudioParameters();
+
+           
             if (this.afterRender) {
                 this.afterRender();
             }
@@ -9299,6 +9314,25 @@ var BABYLON;
             this._lastFrameDuration = BABYLON.Tools.Now - startDate;
         };
 
+        Scene.prototype._updateAudioParameters = function () {
+            var listeningCamera;
+            var audioEngine = this._engine.getAudioEngine();
+
+            if (this.activeCameras.length > 0) {
+                listeningCamera = this.activeCameras[0];
+            } else {
+                listeningCamera = this.activeCamera;
+            }
+
+            if (listeningCamera && audioEngine.canUseWebAudio) {
+                audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
+                var mat = BABYLON.Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+            }
+        };
+
         Scene.prototype.dispose = function () {
             this.beforeRender = null;
             this.afterRender = null;
@@ -9312,6 +9346,8 @@ var BABYLON;
                 this.onDispose();
             }
 
+            this._onBeforeRenderCallbacks = [];
+
             this.detachControl();
 
            
@@ -9980,6 +10016,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getBoundingInfo = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -9994,6 +10034,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getWorldMatrix = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -10154,6 +10198,10 @@ var BABYLON;
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        };
+
+        AbstractMesh.prototype._updateSubMeshesBoundingInfo = function (matrix) {
             if (!this.subMeshes) {
                 return;
             }
@@ -10161,7 +10209,7 @@ var BABYLON;
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         };
 
@@ -10258,7 +10306,7 @@ var BABYLON;
         };
 
         /**
-        * If you'd like to be callbacked after the mesh position or rotation has been updated
+        * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
         * @param func: callback function to add
         */
         AbstractMesh.prototype.registerAfterWorldMatrixUpdate = function (func) {
@@ -10691,9 +10739,7 @@ var BABYLON;
                 }
             }
 
-            while (this._onAfterWorldMatrixUpdate.length > 0) {
-                this._onAfterWorldMatrixUpdate.pop();
-            }
+            this._onAfterWorldMatrixUpdate = [];
 
             this._isDisposed = true;
 
@@ -10744,7 +10790,15 @@ var BABYLON;
             this._batchCache = new _InstancesBatch();
             this._instancesBufferSize = 32 * 16 * 4;
         }
-       
+        Object.defineProperty(Mesh.prototype, "hasLODLevels", {
+           
+            get: function () {
+                return this._LODLevels.length > 0;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Mesh.prototype._sortLODLevels = function () {
             this._LODLevels.sort(function (a, b) {
                 if (a.distance < b.distance) {
@@ -10763,7 +10817,7 @@ var BABYLON;
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -10772,37 +10826,25 @@ var BABYLON;
         };
 
         Mesh.prototype.removeLODLevel = function (mesh) {
-            if (mesh && !mesh._attachedLODLevel) {
-                return this;
-            }
-
-            var index;
-
-            if (mesh) {
-                index = this._LODLevels.indexOf(mesh._attachedLODLevel);
-                mesh._attachedLODLevel = null;
-
-                this._LODLevels.splice(index, 1);
-
-                this._sortLODLevels();
-            } else {
-                for (index = 0; index < this._LODLevels.length; index++) {
-                    if (this._LODLevels[index].mesh === null) {
-                        this._LODLevels.splice(index, 1);
-                        break;
+            for (var index = 0; index < this._LODLevels.length; index++) {
+                if (this._LODLevels[index].mesh === mesh) {
+                    this._LODLevels.splice(index, 1);
+                    if (mesh) {
+                        mesh._masterMesh = null;
                     }
                 }
             }
 
+            this._sortLODLevels();
             return this;
         };
 
-        Mesh.prototype.getLOD = function (camera) {
+        Mesh.prototype.getLOD = function (camera, boundingSphere) {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
             }
 
-            var distanceToCamera = this.getBoundingInfo().boundingSphere.centerWorld.subtract(camera.position).length();
+            var distanceToCamera = (boundingSphere ? boundingSphere : this.getBoundingInfo().boundingSphere).centerWorld.subtract(camera.position).length();
 
             if (this._LODLevels[this._LODLevels.length - 1].distance > distanceToCamera) {
                 return this;
@@ -10813,7 +10855,8 @@ var BABYLON;
 
                 if (level.distance < distanceToCamera) {
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -10890,7 +10933,7 @@ var BABYLON;
 
         Object.defineProperty(Mesh.prototype, "isBlocked", {
             get: function () {
-                return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+                return this._masterMesh !== null && this._masterMesh !== undefined;
             },
             enumerable: true,
             configurable: true
@@ -11154,7 +11197,8 @@ var BABYLON;
         };
 
         Mesh.prototype._renderWithInstances = function (subMesh, fillMode, batch, effect, engine) {
-            var matricesCount = this.instances.length + 1;
+            var visibleInstances = batch.visibleInstances[subMesh._id];
+            var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
 
             while (this._instancesBufferSize < bufferSize) {
@@ -11180,8 +11224,6 @@ var BABYLON;
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
-
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
                     var instance = visibleInstances[instanceIndex];
@@ -11225,7 +11267,7 @@ var BABYLON;
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
            
             var effectiveMaterial = subMesh.getMaterial();
@@ -12003,11 +12045,21 @@ var BABYLON;
         };
 
         InstancedMesh.prototype._preActivate = function () {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         };
 
         InstancedMesh.prototype._activate = function (renderId) {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        };
+
+        InstancedMesh.prototype.getLOD = function (camera) {
+            this._currentLOD = this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD;
         };
 
         InstancedMesh.prototype._syncSubMeshes = function () {
@@ -20023,14 +20075,14 @@ var BABYLON;
                     try  {
                         if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
                             if (onerror) {
-                                onerror(scene);
+                                onerror(scene, 'unable to load the scene');
                             }
 
                             return;
                         }
                     } catch (e) {
                         if (onerror) {
-                            onerror(scene);
+                            onerror(scene, e);
                         }
 
                         return;
@@ -28554,24 +28606,42 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 var BABYLON;
 (function (BABYLON) {
-   
     var AudioEngine = (function () {
         function AudioEngine() {
             this.audioContext = null;
-            this.canUseWebAudio = true;
+            this.canUseWebAudio = false;
             try  {
                 if (typeof AudioContext !== 'undefined') {
                     this.audioContext = new AudioContext();
+                    this.canUseWebAudio = true;
                 } else if (typeof webkitAudioContext !== 'undefined') {
                     this.audioContext = new webkitAudioContext();
-                } else {
-                    this.canUseWebAudio = false;
+                    this.canUseWebAudio = true;
                 }
             } catch (e) {
-               
                 this.canUseWebAudio = false;
             }
+
+           
+            if (this.canUseWebAudio) {
+                this.masterGain = this.audioContext.createGain();
+                this.masterGain.gain.value = 1;
+                this.masterGain.connect(this.audioContext.destination);
+            }
         }
+        AudioEngine.prototype.getGlobalVolume = function () {
+            if (this.canUseWebAudio) {
+                return this.masterGain.gain.value;
+            } else {
+                return -1;
+            }
+        };
+
+        AudioEngine.prototype.setGlobalVolume = function (newVolume) {
+            if (this.canUseWebAudio) {
+                this.masterGain.gain.value = newVolume;
+            }
+        };
         return AudioEngine;
     })();
     BABYLON.AudioEngine = AudioEngine;
@@ -28579,15 +28649,17 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var Sound = (function () {
-        function Sound(url, audioEngine, readyToPlayCallback, distanceMax, autoplay, loop) {
+        function Sound(url, engine, readyToPlayCallback, distanceMax, autoplay, loop) {
             var _this = this;
             this.distanceMax = 10;
             this.autoplay = false;
             this.loop = false;
             this._position = BABYLON.Vector3.Zero();
+            this._orientation = BABYLON.Vector3.Zero();
             this._isLoaded = false;
             this._isReadyToPlay = false;
-            this._audioEngine = audioEngine;
+            this._audioEngine = engine.getAudioEngine();
+            ;
             this._readyToPlayCallback = readyToPlayCallback;
             if (distanceMax)
                 this.distanceMax = distanceMax;
@@ -28595,26 +28667,35 @@ var BABYLON;
                 this.autoplay = autoplay;
             if (loop)
                 this.loop = loop;
-            if (audioEngine.canUseWebAudio) {
+            if (this._audioEngine.canUseWebAudio) {
                 BABYLON.Tools.LoadFile(url, function (data) {
                     _this._soundLoaded(data);
                 }, null, null, true);
             }
         }
         Sound.prototype.setPosition = function (newPosition) {
+            this._position = newPosition;
+
             if (this._isReadyToPlay) {
-                this._position = newPosition;
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
 
+        Sound.prototype.setOrientiation = function (newOrientation) {
+            this._orientation = newOrientation;
+
+            if (this._isReadyToPlay) {
+                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            }
+        };
+
         Sound.prototype.play = function () {
             if (this._isReadyToPlay) {
                 this._soundSource = this._audioEngine.audioContext.createBufferSource();
                 this._soundSource.buffer = this._audioBuffer;
                 this._soundPanner = this._audioEngine.audioContext.createPanner();
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
-                this._soundPanner.connect(this._audioEngine.audioContext.destination);
+                this._soundPanner.connect(this._audioEngine.masterGain);
                 this._soundSource.connect(this._soundPanner);
                 this._soundSource.loop = this.loop;
                 this._soundSource.start(0);
@@ -28627,6 +28708,17 @@ var BABYLON;
         Sound.prototype.pause = function () {
         };
 
+        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+            var _this = this;
+            meshToConnectTo.registerAfterWorldMatrixUpdate(function (connectedMesh) {
+                return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh);
+            });
+        };
+
+        Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
+            this.setPosition(connectedMesh.position);
+        };
+
         Sound.prototype._soundLoaded = function (audioData) {
             var _this = this;
             this._isLoaded = true;
@@ -28637,7 +28729,9 @@ var BABYLON;
                     _this.play();
                 if (_this._readyToPlayCallback)
                     _this._readyToPlayCallback();
-            }, null);
+            }, function (error) {
+                BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
+            });
         };
         return Sound;
     })();

文件差異過大導致無法顯示
+ 9 - 9
babylon.2.0-alpha.js


文件差異過大導致無法顯示
+ 1 - 3957
babylon.2.0.d.ts