Ver código fonte

Fix teture cache issue with RTT

David Catuhe 7 anos atrás
pai
commit
8eedacf04d

Diferenças do arquivo suprimidas por serem muito extensas
+ 12318 - 12318
Playground/babylon.d.txt


Diferenças do arquivo suprimidas por serem muito extensas
+ 11908 - 11908
dist/preview release/babylon.d.ts


Diferenças do arquivo suprimidas por serem muito extensas
+ 28 - 28
dist/preview release/babylon.js


+ 29 - 19
dist/preview release/babylon.max.js

@@ -8130,7 +8130,7 @@ var BABYLON;
             this._currentInstanceBuffers = new Array();
             this._vaoRecordInProgress = false;
             this._mustWipeVertexAttributes = false;
-            this._nextFreeTextureSlot = 0;
+            this._nextFreeTextureSlots = new Array();
             // Hardware supported Compressed Textures
             this._texturesSupported = new Array();
             this._onVRFullScreenTriggered = function () {
@@ -8964,6 +8964,10 @@ var BABYLON;
             this.setDepthBuffer(true);
             this.setDepthFunctionToLessOrEqual();
             this.setDepthWrite(true);
+            // Texture maps
+            for (var slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
         };
         Object.defineProperty(Engine.prototype, "webGLVersion", {
             get: function () {
@@ -9000,7 +9004,10 @@ var BABYLON;
                 }
                 this._boundTexturesCache[key] = null;
             }
-            this._nextFreeTextureSlot = 0;
+            this._nextFreeTextureSlots = [];
+            for (var slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
             this._activeChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
@@ -9467,7 +9474,7 @@ var BABYLON;
                 gl.blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width, texture.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
             }
             if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
-                this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+                this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
                 gl.generateMipmap(gl.TEXTURE_2D);
                 this._bindTextureDirectly(gl.TEXTURE_2D, null);
             }
@@ -11682,7 +11689,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel) {
+            if (this._activeChannel !== channel && channel > -1) {
                 this._gl.activeTexture(this._gl.TEXTURE0 + channel);
                 this._activeChannel = channel;
             }
@@ -11700,12 +11707,15 @@ var BABYLON;
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1) {
                 this._boundTexturesStack.splice(index, 1);
-                this._boundTexturesCache[currentSlot] = null;
+                if (currentSlot > -1) {
+                    this._boundTexturesCache[currentSlot] = null;
+                    this._nextFreeTextureSlots.push(currentSlot);
+                }
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, isPartOfTextureArray) {
-            if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
+        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
+            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
@@ -11716,13 +11726,17 @@ var BABYLON;
                 if (this._activeChannel >= 0) {
                     this._boundTexturesCache[this._activeChannel] = texture;
                     if (isTextureForRendering) {
+                        var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
+                        if (slotIndex > -1) {
+                            this._nextFreeTextureSlots.splice(slotIndex, 1);
+                        }
                         this._boundTexturesStack.push(texture);
                     }
                 }
             }
             if (isTextureForRendering && this._activeChannel > -1) {
                 texture._designatedSlot = this._activeChannel;
-                if (!isPartOfTextureArray) {
+                if (!doNotBindUniformToTextureChannel) {
                     this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
                 }
             }
@@ -11766,20 +11780,16 @@ var BABYLON;
             internalTexture._initialSlot = channel;
             if (channel !== internalTexture._designatedSlot) {
                 if (internalTexture._designatedSlot > -1) {
-                    channel = internalTexture._designatedSlot;
+                    return internalTexture._designatedSlot;
                 }
                 else {
-                    if (this._nextFreeTextureSlot > -1) {
-                        channel = this._nextFreeTextureSlot;
-                        this._nextFreeTextureSlot++;
-                        if (this._nextFreeTextureSlot >= this._caps.maxTexturesImageUnits) {
-                            this._nextFreeTextureSlot = -1; // No more free slots, we will recycle
-                        }
-                    }
-                    else {
-                        channel = this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                        this._textureCollisions.addCount(1, false);
+                    // No slot for this texture, let's pick a new one (if we find a free slot)
+                    if (this._nextFreeTextureSlots.length) {
+                        return this._nextFreeTextureSlots[0];
                     }
+                    // We need to recycle the oldest bound texture, sorry.
+                    this._textureCollisions.addCount(1, false);
+                    return this._removeDesignatedSlot(this._boundTexturesStack[0]);
                 }
             }
             return channel;

Diferenças do arquivo suprimidas por serem muito extensas
+ 28 - 28
dist/preview release/babylon.worker.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 28 - 28
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 29 - 19
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -8130,7 +8130,7 @@ var BABYLON;
             this._currentInstanceBuffers = new Array();
             this._vaoRecordInProgress = false;
             this._mustWipeVertexAttributes = false;
-            this._nextFreeTextureSlot = 0;
+            this._nextFreeTextureSlots = new Array();
             // Hardware supported Compressed Textures
             this._texturesSupported = new Array();
             this._onVRFullScreenTriggered = function () {
@@ -8964,6 +8964,10 @@ var BABYLON;
             this.setDepthBuffer(true);
             this.setDepthFunctionToLessOrEqual();
             this.setDepthWrite(true);
+            // Texture maps
+            for (var slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
         };
         Object.defineProperty(Engine.prototype, "webGLVersion", {
             get: function () {
@@ -9000,7 +9004,10 @@ var BABYLON;
                 }
                 this._boundTexturesCache[key] = null;
             }
-            this._nextFreeTextureSlot = 0;
+            this._nextFreeTextureSlots = [];
+            for (var slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
             this._activeChannel = -1;
         };
         Engine.prototype.isDeterministicLockStep = function () {
@@ -9467,7 +9474,7 @@ var BABYLON;
                 gl.blitFramebuffer(0, 0, texture.width, texture.height, 0, 0, texture.width, texture.height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
             }
             if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
-                this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+                this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
                 gl.generateMipmap(gl.TEXTURE_2D);
                 this._bindTextureDirectly(gl.TEXTURE_2D, null);
             }
@@ -11682,7 +11689,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._activateTextureChannel = function (channel) {
-            if (this._activeChannel !== channel) {
+            if (this._activeChannel !== channel && channel > -1) {
                 this._gl.activeTexture(this._gl.TEXTURE0 + channel);
                 this._activeChannel = channel;
             }
@@ -11700,12 +11707,15 @@ var BABYLON;
             var index = this._boundTexturesStack.indexOf(internalTexture);
             if (index > -1) {
                 this._boundTexturesStack.splice(index, 1);
-                this._boundTexturesCache[currentSlot] = null;
+                if (currentSlot > -1) {
+                    this._boundTexturesCache[currentSlot] = null;
+                    this._nextFreeTextureSlots.push(currentSlot);
+                }
             }
             return currentSlot;
         };
-        Engine.prototype._bindTextureDirectly = function (target, texture, isPartOfTextureArray) {
-            if (isPartOfTextureArray === void 0) { isPartOfTextureArray = false; }
+        Engine.prototype._bindTextureDirectly = function (target, texture, doNotBindUniformToTextureChannel) {
+            if (doNotBindUniformToTextureChannel === void 0) { doNotBindUniformToTextureChannel = false; }
             var currentTextureBound = this._boundTexturesCache[this._activeChannel];
             var isTextureForRendering = texture && texture._initialSlot > -1;
             if (currentTextureBound !== texture) {
@@ -11716,13 +11726,17 @@ var BABYLON;
                 if (this._activeChannel >= 0) {
                     this._boundTexturesCache[this._activeChannel] = texture;
                     if (isTextureForRendering) {
+                        var slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
+                        if (slotIndex > -1) {
+                            this._nextFreeTextureSlots.splice(slotIndex, 1);
+                        }
                         this._boundTexturesStack.push(texture);
                     }
                 }
             }
             if (isTextureForRendering && this._activeChannel > -1) {
                 texture._designatedSlot = this._activeChannel;
-                if (!isPartOfTextureArray) {
+                if (!doNotBindUniformToTextureChannel) {
                     this._bindSamplerUniformToChannel(texture._initialSlot, this._activeChannel);
                 }
             }
@@ -11766,20 +11780,16 @@ var BABYLON;
             internalTexture._initialSlot = channel;
             if (channel !== internalTexture._designatedSlot) {
                 if (internalTexture._designatedSlot > -1) {
-                    channel = internalTexture._designatedSlot;
+                    return internalTexture._designatedSlot;
                 }
                 else {
-                    if (this._nextFreeTextureSlot > -1) {
-                        channel = this._nextFreeTextureSlot;
-                        this._nextFreeTextureSlot++;
-                        if (this._nextFreeTextureSlot >= this._caps.maxTexturesImageUnits) {
-                            this._nextFreeTextureSlot = -1; // No more free slots, we will recycle
-                        }
-                    }
-                    else {
-                        channel = this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                        this._textureCollisions.addCount(1, false);
+                    // No slot for this texture, let's pick a new one (if we find a free slot)
+                    if (this._nextFreeTextureSlots.length) {
+                        return this._nextFreeTextureSlots[0];
                     }
+                    // We need to recycle the oldest bound texture, sorry.
+                    this._textureCollisions.addCount(1, false);
+                    return this._removeDesignatedSlot(this._boundTexturesStack[0]);
                 }
             }
             return channel;

+ 15 - 0
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -0,0 +1,15 @@
+
+declare module BABYLON {
+    class GLTFExport {
+        /**
+         * Exports the geometry of a Mesh array in .gltf file format.
+         * If glb is set to true, exports as .glb.
+         * @param meshes
+         * @param materials
+         * @param glb
+         */
+        static GLTF(meshes: Mesh[], filename: string, glb?: boolean): {
+            [fileName: string]: string | Blob;
+        };
+    }
+}

+ 538 - 0
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -0,0 +1,538 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GLTFExport = /** @class */ (function () {
+        function GLTFExport() {
+        }
+        /**
+         * Exports the geometry of a Mesh array in .gltf file format.
+         * If glb is set to true, exports as .glb.
+         * @param meshes
+         * @param materials
+         * @param glb
+         */
+        GLTFExport.GLTF = function (meshes, filename, glb) {
+            /**
+             * Creates a buffer view based on teh supplied arguments
+             * @param bufferIndex
+             * @param byteOffset
+             * @param byteLength
+             */
+            function createBufferView(bufferIndex, byteOffset, byteLength) {
+                var bufferview = { buffer: bufferIndex, byteLength: byteLength };
+                if (byteOffset > 0) {
+                    bufferview.byteOffset = byteOffset;
+                }
+                return bufferview;
+            }
+            /**
+             * Creates an accessor based on the supplied arguments
+             * @param bufferviewIndex
+             * @param name
+             * @param type
+             * @param componentType
+             * @param count
+             * @param min
+             * @param max
+             */
+            function createAccessor(bufferviewIndex, name, type, componentType, count, min, max) {
+                var accessor = { name: name, bufferView: bufferviewIndex, componentType: componentType, count: count, type: type };
+                if (min) {
+                    accessor.min = min;
+                }
+                if (max) {
+                    accessor.max = max;
+                }
+                return accessor;
+            }
+            /**
+             * Calculates the minimum and maximum values of an array of floats, based on stride
+             * @param buff
+             * @param vertexStart
+             * @param vertexCount
+             * @param arrayOffset
+             * @param stride
+             */
+            function calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride) {
+                var min = [Infinity, Infinity, Infinity];
+                var max = [-Infinity, -Infinity, -Infinity];
+                var end = vertexStart + vertexCount;
+                if (vertexCount > 0) {
+                    for (var i = vertexStart; i < end; ++i) {
+                        var index = stride * i;
+                        for (var j = 0; j < stride; ++j) {
+                            if (buff[index] < min[j]) {
+                                min[j] = buff[index];
+                            }
+                            if (buff[index] > max[j]) {
+                                max[j] = buff[index];
+                            }
+                            ++index;
+                        }
+                    }
+                }
+                return { min: min, max: max };
+            }
+            /**
+             * Write mesh attribute data to buffer.
+             * Returns the bytelength of the data.
+             * @param vertexBufferType
+             * @param submesh
+             * @param meshAttributeArray
+             * @param strideSize
+             * @param byteOffset
+             * @param dataBuffer
+             * @param useRightHandedSystem
+             */
+            function writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem) {
+                var byteOff = byteOffset;
+                var end = submesh.verticesStart + submesh.verticesCount;
+                var byteLength = 0;
+                switch (vertexBufferType) {
+                    case BABYLON.VertexBuffer.PositionKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 12;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.NormalKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 12;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.TangentKind: {
+                        for (var k = submesh.indexStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 16;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.ColorKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 16;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.UVKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 8;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.UV2Kind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 8;
+                        break;
+                    }
+                    default: {
+                        throw new Error("Unsupported vertex buffer type: " + vertexBufferType);
+                    }
+                }
+                return byteLength;
+            }
+            /**
+             * Generates a glb file from the json and binary data.
+             * Returns an object with the glb file name as the key and data as the value.
+             * @param jsonText
+             * @param binaryBuffer
+             * @param glTFPrefix
+             */
+            function createGLB(jsonText, binaryBuffer, glTFPrefix) {
+                var glbFileName = glTFPrefix + '.glb';
+                var headerLength = 12;
+                var chunkLengthPrefix = 8;
+                var jsonLength = jsonText.length;
+                var jsonRemainder = jsonLength % 4;
+                var binRemainder = binaryBuffer.byteLength % 4;
+                var jsonPadding = jsonRemainder === 0 ? jsonRemainder : 4 - jsonRemainder;
+                var binPadding = binRemainder === 0 ? binRemainder : 4 - binRemainder;
+                var totalByteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding;
+                //header
+                var headerBuffer = new ArrayBuffer(headerLength);
+                var headerBufferView = new DataView(headerBuffer);
+                headerBufferView.setUint32(0, 0x46546C67, true); //glTF
+                headerBufferView.setUint32(4, 2, true); // version
+                headerBufferView.setUint32(8, totalByteLength, true); // total bytes in file
+                //json chunk
+                var jsonChunkBuffer = new ArrayBuffer(chunkLengthPrefix + jsonLength + jsonPadding);
+                var jsonChunkBufferView = new DataView(jsonChunkBuffer);
+                jsonChunkBufferView.setUint32(0, jsonLength + jsonPadding, true);
+                jsonChunkBufferView.setUint32(4, 0x4E4F534A, true);
+                //json chunk bytes
+                var jsonData = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix);
+                for (var i = 0; i < jsonLength; ++i) {
+                    jsonData[i] = jsonText.charCodeAt(i);
+                }
+                //json padding
+                var jsonPaddingView = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix + jsonLength);
+                for (var i = 0; i < jsonPadding; ++i) {
+                    jsonPaddingView[i] = 0x20;
+                }
+                //binary chunk
+                var binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
+                var binaryChunkBufferView = new DataView(binaryChunkBuffer);
+                binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength, true);
+                binaryChunkBufferView.setUint32(4, 0x004E4942, true);
+                // binary padding
+                var binPaddingBuffer = new ArrayBuffer(binPadding);
+                var binPaddingView = new Uint8Array(binPaddingBuffer);
+                for (var i = 0; i < binPadding; ++i) {
+                    binPaddingView[i] = 0;
+                }
+                // binary data
+                var glbFile = new Blob([headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer, binPaddingBuffer], { type: 'application/octet-stream' });
+                return _a = {},
+                    _a[glbFileName] = glbFile,
+                    _a;
+                var _a;
+            }
+            /**
+             * Creates a glTF scene based on the array of meshes.
+             * Returns the the total byte offset.
+             * @param gltf
+             * @param totalByteOffset
+             * @param buffer
+             * @param dataBuffer
+             */
+            function createScene(gltf, totalByteOffset, dataBuffer) {
+                var scene = { nodes: new Array() };
+                for (var i = 0; i < meshes.length; ++i) {
+                    // create node to hold translation/rotation/scale and the mesh
+                    var node = { mesh: -1 };
+                    var babylonMesh = meshes[i];
+                    var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
+                    if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
+                        if (useRightHandedSystem) {
+                            node.translation = babylonMesh.position.asArray();
+                        }
+                        else {
+                            node.translation = [babylonMesh.position.x, babylonMesh.position.y, -babylonMesh.position.z];
+                        }
+                    }
+                    if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
+                        if (useRightHandedSystem) {
+                            node.scale = babylonMesh.scaling.asArray();
+                        }
+                        else {
+                            node.scale = [babylonMesh.scaling.x, babylonMesh.scaling.y, -babylonMesh.scaling.z];
+                        }
+                    }
+                    var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
+                    if (babylonMesh.rotationQuaternion) {
+                        rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
+                    }
+                    if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
+                        if (useRightHandedSystem) {
+                            node.rotation = rotationQuaternion.asArray();
+                        }
+                        else {
+                            node.rotation = [-rotationQuaternion.x, -rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w];
+                        }
+                    }
+                    var positionVertexBuffer = void 0;
+                    var positions = void 0;
+                    var positionVertexBufferOffset = void 0;
+                    var positionStrideSize = void 0;
+                    var normalVertexBuffer = void 0;
+                    var normals = void 0;
+                    var normalStrideSize = void 0;
+                    var tangentVertexBuffer = void 0;
+                    var tangents = void 0;
+                    var tangentStrideSize = void 0;
+                    var colorVertexBuffer = void 0;
+                    var colors = void 0;
+                    var colorStrideSize = void 0;
+                    var texCoord0VertexBuffer = void 0;
+                    var texCoords0 = void 0;
+                    var texCoord0StrideSize = void 0;
+                    var texCoord1VertexBuffer = void 0;
+                    var texCoords1 = void 0;
+                    var texCoord1StrideSize = void 0;
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                        positionVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
+                        positions = positionVertexBuffer.getData();
+                        positionVertexBufferOffset = positionVertexBuffer.getOffset();
+                        positionStrideSize = positionVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                        normalVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.NormalKind);
+                        normals = normalVertexBuffer.getData();
+                        normalStrideSize = normalVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
+                        tangentVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.TangentKind);
+                        tangents = tangentVertexBuffer.getData();
+                        tangentStrideSize = tangentVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                        colorVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.ColorKind);
+                        colors = colorVertexBuffer.getData();
+                        colorStrideSize = colorVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                        texCoord0VertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.UVKind);
+                        texCoords0 = texCoord0VertexBuffer.getData();
+                        texCoord0StrideSize = texCoord0VertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                        texCoord1VertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.UV2Kind);
+                        texCoords1 = texCoord1VertexBuffer.getData();
+                        texCoord1StrideSize = texCoord1VertexBuffer.getStrideSize();
+                    }
+                    // create mesh
+                    var mesh = { primitives: new Array() };
+                    mesh.primitives = [];
+                    if (babylonMesh.name) {
+                        mesh.name = babylonMesh.name;
+                    }
+                    // go through all mesh primitives (submeshes)
+                    for (var j = 0; j < babylonMesh.subMeshes.length; ++j) {
+                        var submesh = babylonMesh.subMeshes[j];
+                        var meshPrimitive = { attributes: {} };
+                        // Loop through each attribute of the submesh (mesh primitive)
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.PositionKind, submesh, positions, positionStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 12;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var result = calculateMinMax(positions, submesh.verticesStart, submesh.verticesCount, positionVertexBufferOffset, positionStrideSize);
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Position", "VEC3", 5126, submesh.verticesCount, result.min, result.max);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.POSITION = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.NormalKind, submesh, normals, normalStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 12;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Normal", "VEC3", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.NORMAL = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.TangentKind, submesh, tangents, tangentStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 16;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Tangent", "VEC4", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TANGENT = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.ColorKind, submesh, colors, colorStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 16;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Color", "VEC4", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.COLOR_0 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.UVKind, submesh, texCoords0, texCoord0StrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 8;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Texture Coords", "VEC2", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TEXCOORD_0 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.UV2Kind, submesh, texCoords1, texCoord1StrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 8;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Texture Coords", "VEC2", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TEXCOORD_1 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.getTotalIndices() > 0) {
+                            if (dataBuffer) {
+                                var indices = babylonMesh.getIndices();
+                                var start = submesh.indexStart;
+                                var end = submesh.indexCount + start;
+                                var byteOff = totalByteOffset;
+                                for (var k = start; k < end; k = k + 3) {
+                                    dataBuffer.setUint32(byteOff, indices[k], true);
+                                    byteOff += 4;
+                                    dataBuffer.setUint32(byteOff, indices[k + 1], true);
+                                    byteOff += 4;
+                                    dataBuffer.setUint32(byteOff, indices[k + 2], true);
+                                    byteOff += 4;
+                                }
+                                var byteLength = submesh.indexCount * 4;
+                                totalByteOffset += byteLength;
+                            }
+                            else {
+                                // Create bufferview
+                                var indicesCount = submesh.indexCount;
+                                var byteLength = indicesCount * 4;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Indices", "SCALAR", 5125, indicesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.indices = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.material) {
+                            if (!gltf.materials) {
+                                gltf.materials = new Array();
+                            }
+                            meshPrimitive.material = gltf.materials.length - 1;
+                        }
+                        mesh.primitives.push(meshPrimitive);
+                    }
+                    gltf.meshes.push(mesh);
+                    node.mesh = gltf.meshes.length - 1;
+                    gltf.nodes.push(node);
+                    scene.nodes.push(gltf.nodes.length - 1);
+                }
+                gltf.scenes.push(scene);
+                return totalByteOffset;
+            }
+            var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
+            var gltf = {
+                buffers: new Array(),
+                bufferViews: new Array(),
+                asset: { generator: "BabylonJS", version: "2.0" },
+                meshes: new Array(),
+                scenes: new Array(),
+                nodes: new Array(),
+                accessors: new Array()
+            };
+            var totalByteOffset = 0;
+            var binaryBuffer;
+            var dataBuffer;
+            // Create scene.  First pass calculates the totalByteOffset.
+            totalByteOffset = createScene(gltf, totalByteOffset, null);
+            var buff = { byteLength: totalByteOffset };
+            if (!glb) {
+                buff.uri = glTFPrefix + '.bin';
+            }
+            gltf.buffers.push(buff);
+            var text = JSON.stringify(gltf, null, 2);
+            binaryBuffer = new ArrayBuffer(totalByteOffset);
+            dataBuffer = new DataView(binaryBuffer);
+            totalByteOffset = 0;
+            // Create scene.  Second pass generates the binary data
+            createScene(gltf, totalByteOffset, dataBuffer);
+            if (glb) {
+                var glbFile = createGLB(text, binaryBuffer, glTFPrefix);
+                return glbFile;
+            }
+            var glTFFileName = glTFPrefix + '.gltf';
+            var glTFBinFile = glTFPrefix + '.bin';
+            var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
+            return _a = {},
+                _a[glTFFileName] = text,
+                _a[glTFBinFile] = bin,
+                _a;
+            var _a;
+        };
+        return GLTFExport;
+    }());
+    BABYLON.GLTFExport = GLTFExport;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFSerializer.js.map

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 0
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 539 - 0
dist/preview release/serializers/babylonjs.serializers.js

@@ -143,6 +143,545 @@ var BABYLON;
 //# sourceMappingURL=babylon.objSerializer.js.map
 
 
+var BABYLON;
+(function (BABYLON) {
+    var GLTFExport = /** @class */ (function () {
+        function GLTFExport() {
+        }
+        /**
+         * Exports the geometry of a Mesh array in .gltf file format.
+         * If glb is set to true, exports as .glb.
+         * @param meshes
+         * @param materials
+         * @param glb
+         */
+        GLTFExport.GLTF = function (meshes, filename, glb) {
+            /**
+             * Creates a buffer view based on teh supplied arguments
+             * @param bufferIndex
+             * @param byteOffset
+             * @param byteLength
+             */
+            function createBufferView(bufferIndex, byteOffset, byteLength) {
+                var bufferview = { buffer: bufferIndex, byteLength: byteLength };
+                if (byteOffset > 0) {
+                    bufferview.byteOffset = byteOffset;
+                }
+                return bufferview;
+            }
+            /**
+             * Creates an accessor based on the supplied arguments
+             * @param bufferviewIndex
+             * @param name
+             * @param type
+             * @param componentType
+             * @param count
+             * @param min
+             * @param max
+             */
+            function createAccessor(bufferviewIndex, name, type, componentType, count, min, max) {
+                var accessor = { name: name, bufferView: bufferviewIndex, componentType: componentType, count: count, type: type };
+                if (min) {
+                    accessor.min = min;
+                }
+                if (max) {
+                    accessor.max = max;
+                }
+                return accessor;
+            }
+            /**
+             * Calculates the minimum and maximum values of an array of floats, based on stride
+             * @param buff
+             * @param vertexStart
+             * @param vertexCount
+             * @param arrayOffset
+             * @param stride
+             */
+            function calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride) {
+                var min = [Infinity, Infinity, Infinity];
+                var max = [-Infinity, -Infinity, -Infinity];
+                var end = vertexStart + vertexCount;
+                if (vertexCount > 0) {
+                    for (var i = vertexStart; i < end; ++i) {
+                        var index = stride * i;
+                        for (var j = 0; j < stride; ++j) {
+                            if (buff[index] < min[j]) {
+                                min[j] = buff[index];
+                            }
+                            if (buff[index] > max[j]) {
+                                max[j] = buff[index];
+                            }
+                            ++index;
+                        }
+                    }
+                }
+                return { min: min, max: max };
+            }
+            /**
+             * Write mesh attribute data to buffer.
+             * Returns the bytelength of the data.
+             * @param vertexBufferType
+             * @param submesh
+             * @param meshAttributeArray
+             * @param strideSize
+             * @param byteOffset
+             * @param dataBuffer
+             * @param useRightHandedSystem
+             */
+            function writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem) {
+                var byteOff = byteOffset;
+                var end = submesh.verticesStart + submesh.verticesCount;
+                var byteLength = 0;
+                switch (vertexBufferType) {
+                    case BABYLON.VertexBuffer.PositionKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 12;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.NormalKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 12;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.TangentKind: {
+                        for (var k = submesh.indexStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            if (useRightHandedSystem) {
+                                dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            }
+                            else {
+                                dataBuffer.setFloat32(byteOff, -meshAttributeArray[index + 2], true);
+                            }
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 16;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.ColorKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 2], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 3], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 16;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.UVKind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 8;
+                        break;
+                    }
+                    case BABYLON.VertexBuffer.UV2Kind: {
+                        for (var k = submesh.verticesStart; k < end; ++k) {
+                            var index = k * strideSize;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index], true);
+                            byteOff += 4;
+                            dataBuffer.setFloat32(byteOff, meshAttributeArray[index + 1], true);
+                            byteOff += 4;
+                        }
+                        byteLength = submesh.verticesCount * 8;
+                        break;
+                    }
+                    default: {
+                        throw new Error("Unsupported vertex buffer type: " + vertexBufferType);
+                    }
+                }
+                return byteLength;
+            }
+            /**
+             * Generates a glb file from the json and binary data.
+             * Returns an object with the glb file name as the key and data as the value.
+             * @param jsonText
+             * @param binaryBuffer
+             * @param glTFPrefix
+             */
+            function createGLB(jsonText, binaryBuffer, glTFPrefix) {
+                var glbFileName = glTFPrefix + '.glb';
+                var headerLength = 12;
+                var chunkLengthPrefix = 8;
+                var jsonLength = jsonText.length;
+                var jsonRemainder = jsonLength % 4;
+                var binRemainder = binaryBuffer.byteLength % 4;
+                var jsonPadding = jsonRemainder === 0 ? jsonRemainder : 4 - jsonRemainder;
+                var binPadding = binRemainder === 0 ? binRemainder : 4 - binRemainder;
+                var totalByteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding;
+                //header
+                var headerBuffer = new ArrayBuffer(headerLength);
+                var headerBufferView = new DataView(headerBuffer);
+                headerBufferView.setUint32(0, 0x46546C67, true); //glTF
+                headerBufferView.setUint32(4, 2, true); // version
+                headerBufferView.setUint32(8, totalByteLength, true); // total bytes in file
+                //json chunk
+                var jsonChunkBuffer = new ArrayBuffer(chunkLengthPrefix + jsonLength + jsonPadding);
+                var jsonChunkBufferView = new DataView(jsonChunkBuffer);
+                jsonChunkBufferView.setUint32(0, jsonLength + jsonPadding, true);
+                jsonChunkBufferView.setUint32(4, 0x4E4F534A, true);
+                //json chunk bytes
+                var jsonData = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix);
+                for (var i = 0; i < jsonLength; ++i) {
+                    jsonData[i] = jsonText.charCodeAt(i);
+                }
+                //json padding
+                var jsonPaddingView = new Uint8Array(jsonChunkBuffer, chunkLengthPrefix + jsonLength);
+                for (var i = 0; i < jsonPadding; ++i) {
+                    jsonPaddingView[i] = 0x20;
+                }
+                //binary chunk
+                var binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
+                var binaryChunkBufferView = new DataView(binaryChunkBuffer);
+                binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength, true);
+                binaryChunkBufferView.setUint32(4, 0x004E4942, true);
+                // binary padding
+                var binPaddingBuffer = new ArrayBuffer(binPadding);
+                var binPaddingView = new Uint8Array(binPaddingBuffer);
+                for (var i = 0; i < binPadding; ++i) {
+                    binPaddingView[i] = 0;
+                }
+                // binary data
+                var glbFile = new Blob([headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer, binPaddingBuffer], { type: 'application/octet-stream' });
+                return _a = {},
+                    _a[glbFileName] = glbFile,
+                    _a;
+                var _a;
+            }
+            /**
+             * Creates a glTF scene based on the array of meshes.
+             * Returns the the total byte offset.
+             * @param gltf
+             * @param totalByteOffset
+             * @param buffer
+             * @param dataBuffer
+             */
+            function createScene(gltf, totalByteOffset, dataBuffer) {
+                var scene = { nodes: new Array() };
+                for (var i = 0; i < meshes.length; ++i) {
+                    // create node to hold translation/rotation/scale and the mesh
+                    var node = { mesh: -1 };
+                    var babylonMesh = meshes[i];
+                    var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
+                    if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
+                        if (useRightHandedSystem) {
+                            node.translation = babylonMesh.position.asArray();
+                        }
+                        else {
+                            node.translation = [babylonMesh.position.x, babylonMesh.position.y, -babylonMesh.position.z];
+                        }
+                    }
+                    if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
+                        if (useRightHandedSystem) {
+                            node.scale = babylonMesh.scaling.asArray();
+                        }
+                        else {
+                            node.scale = [babylonMesh.scaling.x, babylonMesh.scaling.y, -babylonMesh.scaling.z];
+                        }
+                    }
+                    var rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(babylonMesh.rotation.y, babylonMesh.rotation.x, babylonMesh.rotation.z);
+                    if (babylonMesh.rotationQuaternion) {
+                        rotationQuaternion = rotationQuaternion.multiply(babylonMesh.rotationQuaternion);
+                    }
+                    if (!(rotationQuaternion.x === 0 && rotationQuaternion.y === 0 && rotationQuaternion.z === 0 && rotationQuaternion.w === 1)) {
+                        if (useRightHandedSystem) {
+                            node.rotation = rotationQuaternion.asArray();
+                        }
+                        else {
+                            node.rotation = [-rotationQuaternion.x, -rotationQuaternion.y, rotationQuaternion.z, rotationQuaternion.w];
+                        }
+                    }
+                    var positionVertexBuffer = void 0;
+                    var positions = void 0;
+                    var positionVertexBufferOffset = void 0;
+                    var positionStrideSize = void 0;
+                    var normalVertexBuffer = void 0;
+                    var normals = void 0;
+                    var normalStrideSize = void 0;
+                    var tangentVertexBuffer = void 0;
+                    var tangents = void 0;
+                    var tangentStrideSize = void 0;
+                    var colorVertexBuffer = void 0;
+                    var colors = void 0;
+                    var colorStrideSize = void 0;
+                    var texCoord0VertexBuffer = void 0;
+                    var texCoords0 = void 0;
+                    var texCoord0StrideSize = void 0;
+                    var texCoord1VertexBuffer = void 0;
+                    var texCoords1 = void 0;
+                    var texCoord1StrideSize = void 0;
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                        positionVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.PositionKind);
+                        positions = positionVertexBuffer.getData();
+                        positionVertexBufferOffset = positionVertexBuffer.getOffset();
+                        positionStrideSize = positionVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                        normalVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.NormalKind);
+                        normals = normalVertexBuffer.getData();
+                        normalStrideSize = normalVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
+                        tangentVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.TangentKind);
+                        tangents = tangentVertexBuffer.getData();
+                        tangentStrideSize = tangentVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                        colorVertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.ColorKind);
+                        colors = colorVertexBuffer.getData();
+                        colorStrideSize = colorVertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                        texCoord0VertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.UVKind);
+                        texCoords0 = texCoord0VertexBuffer.getData();
+                        texCoord0StrideSize = texCoord0VertexBuffer.getStrideSize();
+                    }
+                    if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                        texCoord1VertexBuffer = babylonMesh.getVertexBuffer(BABYLON.VertexBuffer.UV2Kind);
+                        texCoords1 = texCoord1VertexBuffer.getData();
+                        texCoord1StrideSize = texCoord1VertexBuffer.getStrideSize();
+                    }
+                    // create mesh
+                    var mesh = { primitives: new Array() };
+                    mesh.primitives = [];
+                    if (babylonMesh.name) {
+                        mesh.name = babylonMesh.name;
+                    }
+                    // go through all mesh primitives (submeshes)
+                    for (var j = 0; j < babylonMesh.subMeshes.length; ++j) {
+                        var submesh = babylonMesh.subMeshes[j];
+                        var meshPrimitive = { attributes: {} };
+                        // Loop through each attribute of the submesh (mesh primitive)
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.PositionKind, submesh, positions, positionStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 12;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var result = calculateMinMax(positions, submesh.verticesStart, submesh.verticesCount, positionVertexBufferOffset, positionStrideSize);
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Position", "VEC3", 5126, submesh.verticesCount, result.min, result.max);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.POSITION = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.NormalKind, submesh, normals, normalStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 12;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Normal", "VEC3", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.NORMAL = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.TangentKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.TangentKind, submesh, tangents, tangentStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 16;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Tangent", "VEC4", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TANGENT = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.ColorKind, submesh, colors, colorStrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 16;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Color", "VEC4", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.COLOR_0 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.UVKind, submesh, texCoords0, texCoord0StrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 8;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Texture Coords", "VEC2", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TEXCOORD_0 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                            if (dataBuffer) {
+                                totalByteOffset += writeAttributeData(BABYLON.VertexBuffer.UV2Kind, submesh, texCoords1, texCoord1StrideSize, totalByteOffset, dataBuffer, useRightHandedSystem);
+                            }
+                            else {
+                                // Create bufferview
+                                var byteLength = submesh.verticesCount * 8;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Texture Coords", "VEC2", 5126, submesh.verticesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.attributes.TEXCOORD_1 = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.getTotalIndices() > 0) {
+                            if (dataBuffer) {
+                                var indices = babylonMesh.getIndices();
+                                var start = submesh.indexStart;
+                                var end = submesh.indexCount + start;
+                                var byteOff = totalByteOffset;
+                                for (var k = start; k < end; k = k + 3) {
+                                    dataBuffer.setUint32(byteOff, indices[k], true);
+                                    byteOff += 4;
+                                    dataBuffer.setUint32(byteOff, indices[k + 1], true);
+                                    byteOff += 4;
+                                    dataBuffer.setUint32(byteOff, indices[k + 2], true);
+                                    byteOff += 4;
+                                }
+                                var byteLength = submesh.indexCount * 4;
+                                totalByteOffset += byteLength;
+                            }
+                            else {
+                                // Create bufferview
+                                var indicesCount = submesh.indexCount;
+                                var byteLength = indicesCount * 4;
+                                var bufferview = createBufferView(0, totalByteOffset, byteLength);
+                                totalByteOffset += byteLength;
+                                gltf.bufferViews.push(bufferview);
+                                // Create accessor
+                                var accessor = createAccessor(gltf.bufferViews.length - 1, "Indices", "SCALAR", 5125, indicesCount);
+                                gltf.accessors.push(accessor);
+                                meshPrimitive.indices = gltf.accessors.length - 1;
+                            }
+                        }
+                        if (babylonMesh.material) {
+                            if (!gltf.materials) {
+                                gltf.materials = new Array();
+                            }
+                            meshPrimitive.material = gltf.materials.length - 1;
+                        }
+                        mesh.primitives.push(meshPrimitive);
+                    }
+                    gltf.meshes.push(mesh);
+                    node.mesh = gltf.meshes.length - 1;
+                    gltf.nodes.push(node);
+                    scene.nodes.push(gltf.nodes.length - 1);
+                }
+                gltf.scenes.push(scene);
+                return totalByteOffset;
+            }
+            var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
+            var gltf = {
+                buffers: new Array(),
+                bufferViews: new Array(),
+                asset: { generator: "BabylonJS", version: "2.0" },
+                meshes: new Array(),
+                scenes: new Array(),
+                nodes: new Array(),
+                accessors: new Array()
+            };
+            var totalByteOffset = 0;
+            var binaryBuffer;
+            var dataBuffer;
+            // Create scene.  First pass calculates the totalByteOffset.
+            totalByteOffset = createScene(gltf, totalByteOffset, null);
+            var buff = { byteLength: totalByteOffset };
+            if (!glb) {
+                buff.uri = glTFPrefix + '.bin';
+            }
+            gltf.buffers.push(buff);
+            var text = JSON.stringify(gltf, null, 2);
+            binaryBuffer = new ArrayBuffer(totalByteOffset);
+            dataBuffer = new DataView(binaryBuffer);
+            totalByteOffset = 0;
+            // Create scene.  Second pass generates the binary data
+            createScene(gltf, totalByteOffset, dataBuffer);
+            if (glb) {
+                var glbFile = createGLB(text, binaryBuffer, glTFPrefix);
+                return glbFile;
+            }
+            var glTFFileName = glTFPrefix + '.gltf';
+            var glTFBinFile = glTFPrefix + '.bin';
+            var bin = new Blob([binaryBuffer], { type: 'application/octet-stream' });
+            return _a = {},
+                _a[glTFFileName] = text,
+                _a[glTFBinFile] = bin,
+                _a;
+            var _a;
+        };
+        return GLTFExport;
+    }());
+    BABYLON.GLTFExport = GLTFExport;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFSerializer.js.map
+
+
 (function universalModuleDefinition(root, factory) {
                 var f = factory();
                 if (root && root["BABYLON"]) {

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 16 - 0
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -10,3 +10,19 @@ declare module BABYLON {
         static MTL(mesh: Mesh): string;
     }
 }
+
+
+declare module BABYLON {
+    class GLTFExport {
+        /**
+         * Exports the geometry of a Mesh array in .gltf file format.
+         * If glb is set to true, exports as .glb.
+         * @param meshes
+         * @param materials
+         * @param glb
+         */
+        static GLTF(meshes: Mesh[], filename: string, glb?: boolean): {
+            [fileName: string]: string | Blob;
+        };
+    }
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 28 - 28
dist/preview release/viewer/babylon.viewer.js


+ 32 - 19
src/Engine/babylon.engine.ts

@@ -791,7 +791,7 @@
 
         private _frameHandler: number;
 
-        private _nextFreeTextureSlot = 0;
+        private _nextFreeTextureSlots = new Array<number>();
 
         // Hardware supported Compressed Textures
         private _texturesSupported = new Array<string>();
@@ -1296,6 +1296,11 @@
             this.setDepthBuffer(true);
             this.setDepthFunctionToLessOrEqual();
             this.setDepthWrite(true);
+
+            // Texture maps
+            for (let slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
         }
 
         public get webGLVersion(): number {
@@ -1330,7 +1335,10 @@
                 }
                 this._boundTexturesCache[key] = null;
             }
-            this._nextFreeTextureSlot = 0;
+            this._nextFreeTextureSlots = [];
+            for (let slot = 0; slot < this._caps.maxTexturesImageUnits; slot++) {
+                this._nextFreeTextureSlots.push(slot);
+            }
             this._activeChannel = -1;
         }
 
@@ -1891,7 +1899,7 @@
             }
 
             if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
-                this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+                this._bindTextureDirectly(gl.TEXTURE_2D, texture, true);
                 gl.generateMipmap(gl.TEXTURE_2D);
                 this._bindTextureDirectly(gl.TEXTURE_2D, null);
             }
@@ -4596,7 +4604,7 @@
         }
 
         private _activateTextureChannel(channel: number): void {
-            if (this._activeChannel !== channel) {
+            if (this._activeChannel !== channel && channel > -1) {
                 this._gl.activeTexture(this._gl.TEXTURE0 + channel);
                 this._activeChannel = channel;
             }
@@ -4618,13 +4626,16 @@
 
             if (index > -1) {
                 this._boundTexturesStack.splice(index, 1);
-                this._boundTexturesCache[currentSlot] = null;
+                if (currentSlot > -1) {
+                    this._boundTexturesCache[currentSlot] = null;
+                    this._nextFreeTextureSlots.push(currentSlot);
+                }
             }
 
             return currentSlot;
         }
 
-        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, isPartOfTextureArray = false): void {
+        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, doNotBindUniformToTextureChannel = false): void {
             let currentTextureBound = this._boundTexturesCache[this._activeChannel];
             let isTextureForRendering = texture && texture._initialSlot > -1;
 
@@ -4639,6 +4650,10 @@
                     this._boundTexturesCache[this._activeChannel] = texture;
 
                     if (isTextureForRendering) {
+                        let slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
+                        if (slotIndex > -1) {
+                            this._nextFreeTextureSlots.splice(slotIndex, 1);
+                        }
                         this._boundTexturesStack.push(texture!);
                     }
                 }
@@ -4646,7 +4661,7 @@
 
             if (isTextureForRendering && this._activeChannel > -1) {
                 texture!._designatedSlot = this._activeChannel;
-                if (!isPartOfTextureArray) {
+                if (!doNotBindUniformToTextureChannel) {
                     this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
                 }
             }
@@ -4692,7 +4707,7 @@
             this._setTexture(channel, texture);
         }
 
-        private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>) {
+        private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
             if (!internalTexture) {
                 return -1;
             }
@@ -4701,18 +4716,16 @@
 
             if (channel !== internalTexture._designatedSlot) {
                 if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
-                    channel = internalTexture._designatedSlot;
-                } else { // Not slot for this texture, let's pick a new one
-                    if (this._nextFreeTextureSlot > -1) { // We can use a free slot
-                        channel = this._nextFreeTextureSlot;
-                        this._nextFreeTextureSlot++;
-                        if (this._nextFreeTextureSlot >= this._caps.maxTexturesImageUnits) {
-                            this._nextFreeTextureSlot = -1; // No more free slots, we will recycle
-                        }
-                    } else { // We need to recycle the oldest bound texture, sorry.
-                        channel = this._removeDesignatedSlot(this._boundTexturesStack[0]);
-                        this._textureCollisions.addCount(1, false);
+                    return internalTexture._designatedSlot;
+                } else {
+                    // No slot for this texture, let's pick a new one (if we find a free slot)
+                    if (this._nextFreeTextureSlots.length) {
+                        return this._nextFreeTextureSlots[0];
                     }
+
+                    // We need to recycle the oldest bound texture, sorry.
+                    this._textureCollisions.addCount(1, false);
+                    return this._removeDesignatedSlot(this._boundTexturesStack[0]);
                 }
             }