Jelajahi Sumber

Merge pull request #5024 from kcoley/textureTransform

glTFSerializer: Add texture transform support
David Catuhe 7 tahun lalu
induk
melakukan
90a866a683

+ 18 - 6
Playground/js/index.js

@@ -548,6 +548,7 @@ function showError(errorMessage, errorEvent) {
                 document.getElementById("errorZone").innerHTML = "";
                 document.getElementById("statusBar").innerHTML = "Loading assets...Please wait";
                 var checkCamera = true;
+                var checkSceneCount = true;
                 var wrappedEval = false;
                 var createEngineFunction = "createDefaultEngine";
                 var createSceneFunction;
@@ -596,6 +597,12 @@ function showError(errorMessage, errorEvent) {
                         //create scene
                         eval("scene = " + createSceneFunction + "()");
 
+                        // if scene returns a promise avoid checks
+                        if(scene.then){
+                            checkCamera = false
+                            checkSceneCount = false
+                        }
+
                         if (!scene) {
                             showError(createSceneFunction + " function must return a scene.", null);
                             return;
@@ -630,8 +637,9 @@ function showError(errorMessage, errorEvent) {
                         fpsLabel.style.right = document.body.clientWidth - (jsEditor.domElement.clientWidth + canvas.clientWidth) + "px";
                         fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
                     });
+    
+                    if (checkSceneCount && engine.scenes.length === 0) {
 
-                    if (engine.scenes.length === 0) {
                         showError("You must at least create a scene.", null);
                         return;
                     }
@@ -639,11 +647,15 @@ function showError(errorMessage, errorEvent) {
                     if (checkCamera && engine.scenes[0].activeCamera == null) {
                         showError("You must at least create a camera.", null);
                         return;
-                    }
-
-                    engine.scenes[0].executeWhenReady(function () {
-                        document.getElementById("statusBar").innerHTML = "";
-                    });
+                    }else if(scene.then){
+                        scene.then(function (){
+                            document.getElementById("statusBar").innerHTML = "";
+                        });
+                    }else{
+                        engine.scenes[0].executeWhenReady(function () {
+                            document.getElementById("statusBar").innerHTML = "";
+                        });
+                    }           
 
                     if (scene) {
                         if (showInspector) {

+ 7 - 1
Tools/Gulp/config.json

@@ -1868,7 +1868,13 @@
                     "../../serializers/src/glTF/2.0/babylon.glTFData.ts",
                     "../../serializers/src/glTF/2.0/babylon.glTFMaterialExporter.ts",
                     "../../serializers/src/glTF/2.0/babylon.glTFAnimation.ts",
-                    "../../serializers/src/glTF/2.0/babylon.glTFUtilities.ts"
+                    "../../serializers/src/glTF/2.0/babylon.glTFUtilities.ts",
+                    "../../serializers/src/glTF/2.0/babylon.glTFExporterExtension.ts",
+                    "../../serializers/src/glTF/babylon.glTFFileExporter.ts",
+                    "../../serializers/src/glTF/2.0/Extensions/KHR_texture_transform.ts"
+                ],
+                "shaderFiles": [
+                    "../../serializers/src/glTF/2.0/shaders/textureTransform.fragment.fx"
                 ],
                 "output": "babylon.glTF2Serializer.js"
             }

+ 249 - 246
dist/preview release/what's new.md

@@ -1,246 +1,249 @@
-# 3.3.0
-
-## Major updates
-
-- GUI
-  - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
-  - New GUI control: [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-  - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
-  -New GUI container [SelectionPanel](http://doc.babylonjs.com/how_to/selector) ([JohnK](https://github.com/BabylonJSGuide))
-- Gizmo Support ([TrevorDev](https://github.com/TrevorDev))
-  - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
-  - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
-  - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
-  - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
-  - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
-  - Added ignoreChildren field to bounding box to save performance when using heavily nested meshes ([TrevorDev](https://github.com/TrevorDev))
-  - Add uniform scaling drag support to scale gizmo ([TrevorDev](https://github.com/TrevorDev))
-  - Support interacting with child elements ([TrevorDev](https://github.com/TrevorDev))
-  - BoundingBox gizmo support for including/excluding descendants when computing the bounding box ([TrevorDev](https://github.com/TrevorDev))
-- Particle system improvements ([Deltakosh](https://github.com/deltakosh))
-  - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
-  - Improved CPU particles rendering performance (up to x2 on low end devices)
-  - Added support for `isBillboardBased`. [Doc](http://doc.babylonjs.com/babylon101/particles#alignment)
-  - Added support for billboard mode. [Doc](https://doc.babylonjs.com/babylon101/particles#alignment)
-  - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
-  - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
-  - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
-  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
-  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
-  - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
-  - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
-  - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
-  - Added support for `minInitialRotation` and `maxInitialRotation`. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-  - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
-  - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
-  - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-  - Added support for velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
-  - Added support for limit velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
-  - Added support for drag gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#drag-factor)
-  - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
-  - Added support for emit rate gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#emit-rate-over-time)
-  - Added support for ramp gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#ramp-gradients)
-  - Start size gradient support for particles. [Doc](http://doc.babylonjs.com/babylon101/particles#start-size-over-time) ([TrevorDev](https://github.com/TrevorDev))
-  - Attached sub emitters. [Doc](http://doc.babylonjs.com/how_to/sub_emitters) ([TrevorDev](https://github.com/TrevorDev))
-  - Cylinder particle emitter and constructor in baseParticle [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
-  - Added support for cylinder particle emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
-  - Added support for random start cell when using animated sprite sheets. [Doc](http://doc.babylonjs.com/how_to/animate)
-- Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
-- Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
-- Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
-- GUI and Inspector are now ES-Modules ([RaananW](https://github.com/RaananW))
-- Added support for noise procedural textures. [Doc](http://doc.babylonjs.com/how_to/how_to_use_procedural_textures#noise-procedural-texture) ([Deltakosh](https://github.com/deltakosh))
-- Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
-- Added Video Recorder [Documentation](https://doc.babylonjs.com/How_To/Render_Scene_on_a_Video) ([sebavan](http://www.github.com/sebavan))
-
-## Updates
-
-- Updated TypeScript version to new major 3.0.1 ([christopherstock](https://github.com/christopherstock))
-- All NPM packages have `latest` and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
-- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
-- Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
-
-### GUI
-- Added dead key support and before key add observable to InputText. [Doc](https://doc.babylonjs.com/how_to/gui#using-onbeforekeyaddobservable-for-extended-keyboard-layouts-and-input-masks)([theom](https://github.com/theom))
-- Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
-- New vertical mode for sliders in 2D GUI. [Demo](https://www.babylonjs-playground.com/#U9AC0N#53) ([Saket Saurabh](https://github.com/ssaket))
-- Added `isEnabled` and `disabledColor` property to Gui Control ([barteq100](https://github.com/barteq100))
-- Added support for connecting multiple InputText controls to VirtualKeyboard and can disconnect individual InputTexts. ([brian Zinn](https://github.com/brianzinn))
-
-### Core Engine
-
-- Improved the way world matrices were computed ([Deltakosh](https://github.com/deltakosh))
-- Added `scene.rootNodes` to track root nodes (ie. nodes with no parent) ([Deltakosh](https://github.com/deltakosh))
-- Added `scene.pickSpriteWithRay` function ([Deltakosh](https://github.com/deltakosh))
-- Added support for multiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
-- Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
-- Added new `BoundingInfo.scale()` function to let users control the size of the bounding info ([Deltakosh](https://github.com/deltakosh))
-- Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))
-- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catmull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
-- Added support for specifying the center of rotation to textures ([bghgary](http://www.github.com/bghgary))
-- Added webVR support for Oculus Go ([TrevorDev](https://github.com/TrevorDev))
-- Added ability to not generate polynomials harmonics upon prefiltered texture creation ([sebavan](http://www.github.com/sebavan))
-- Added predicate function to customize the list of mesh included in the computation of bounding vectors in the ```getHierarchyBoundingVectors``` method ([sebavan](http://www.github.com/sebavan))
-- Added webVR constructor options: disable laser pointer toggle, teleportation floor meshes ([TrevorDev](https://github.com/TrevorDev))
-- Get a root mesh from an asset container, load a mesh from a file with a single string url ([TrevorDev](https://github.com/TrevorDev))
-- UtilityLayer class to render another scene as a layer on top of an existing scene ([TrevorDev](https://github.com/TrevorDev))
-- AnimationGroup has now onAnimationGroupEnd observable ([RaananW](https://github.com/RaananW))
-- New `serialize` and `Parse` functions to serialize and parse all procedural textures from the Procedural Textures Library ([julien-moreau](https://github.com/julien-moreau))
-- Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
-- AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
-- Added sprite isVisible field ([TrevorDev](https://github.com/TrevorDev))
-- EnvironmentHelper will recreate ground and skybox meshes if force-disposed ([RaananW](https://github.com/RaananW))
-- Added viewport caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
-- Added unpackFlipY caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
-- Added rebind optimization of video texture ([sebavan](http://www.github.com/sebavan))
-- Fix Background Material effect caching ([sebavan](http://www.github.com/sebavan))
-- Prevent texture ```getSize``` to generate garbage collection ([sebavan](http://www.github.com/sebavan))
-- Prevent ```lodGenerationScale``` and ```lodGenerationOffset``` to force rebind ([sebavan](http://www.github.com/sebavan))
-- Added poster property on VideoTexture ([sebavan](http://www.github.com/sebavan))
-- Added ```onUserActionRequestedObservable``` to workaround and detect autoplay video policy restriction on VideoTexture ([sebavan](http://www.github.com/sebavan))
-- `Sound` now accepts `MediaStream` as source to enable easier WebAudio and WebRTC integrations ([menduz](https://github.com/menduz))
-- Vector x, y and z constructor parameters are now optional and default to 0 ([TrevorDev](https://github.com/TrevorDev))
-- Added and removed camera methods in the default pipeline ([TrevorDev](https://github.com/TrevorDev))
-- Added internal texture `format` support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
-- Added canvas toBlob polyfill in tools ([sebavan](http://www.github.com/sebavan))
-- Added `RawCubeTexture` class with RGBD and mipmap support ([bghgary](http://www.github.com/bghgary))
-- Added effect layer per rendering group addressing [Issue 4463](https://github.com/BabylonJS/Babylon.js/issues/4463) ([sebavan](http://www.github.com/sebavan))
-- Added predicate function `targetMask` argument to `scene.beginWeightedAnimation`, `scene.beginAnimation`, `scene.stopAnimation`, and `animatable.stop` to allow for selective application of animations.  ([fmmoret](http://github.com/fmmoret))
-- Oculus GO and GearVR 3dof controllers will now rotate with the user's head if they turn around in their room ([TrevorDev](https://github.com/TrevorDev))
-- Added onPoseUpdatedFromDeviceObservable to webVRCamera to detect when the camera's pose has been updated ([TrevorDev](https://github.com/TrevorDev))
-- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
-- Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
-- Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
-- Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
-- Added ACES ToneMapping to the image processing to help getting more parity with other engines ([sebavan](http://www.github.com/sebavan))
-- Added Image Processing to the particle system to allow consistency in one pass forward rendering scenes ([sebavan](http://www.github.com/sebavan))
-- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
-- Added support for main WebGL2 texture formats ([PeapBoy](https://github.com/NicolasBuecher))
-- Added fadeInOutBehavior and tooltipText for holographic buttons ([TrevorDev](https://github.com/TrevorDev))
-- StartDrag method added to pointerDragBehavior to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
-- Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
-- Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
-- BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))
-- Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
-- Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
-- Improved performance of cached nodes but ensuring parent always updates cache. This removes failed isSynchronized test that meant computeWorldMatrix would always have to rebuild. On large scenes this could double framerate. ([Bolloxim](https://github.com/Bolloxim))
-- Added FXAA and MSAA support to the StandardRenderingPipeline ([julien-moreau](https://github.com/julien-moreau))
-- Make teleportCamera public in VR experience helper ([TrevorDev](https://github.com/TrevorDev))
-
-
-### glTF Loader
-
-- Added support for KHR_texture_transform ([bghgary](http://www.github.com/bghgary))
-- Added `onNodeLODsLoadedObservable` and `onMaterialLODsLoadedObservable` to MSFT_lod loader extension ([bghgary](http://www.github.com/bghgary))
-- Added glTF loader settings to the GLTF tab in the debug layer ([bghgary](http://www.github.com/bghgary))
-- Added debug logging and performance counters ([bghgary](http://www.github.com/bghgary))
-- Added support for EXT_lights_imageBased ([bghgary](http://www.github.com/bghgary))
-- Added support for MSFT_audio_emitter ([najadojo](http://www.github.com/najadojo))
-- Added support for custom loader extensions ([bghgary](http://www.github.com/bghgary))
-
-### Viewer
-
-- No fullscreen button on small devices ([RaananW](https://github.com/RaananW))
-- Nav-Bar is now displayed on fullscreen per default ([RaananW](https://github.com/RaananW))
-- Viewer configuration supports deprecated values using the new configurationCompatibility processor  ([RaananW](https://github.com/RaananW))
-- Shadows will only render while models are entering the scene or animating ([RaananW](https://github.com/RaananW))
-- Support for model drag and drop onto the canvas ([RaananW](https://github.com/RaananW))
-- New lab feature - global light rotation [#4347](https://github.com/BabylonJS/Babylon.js/issues/4347) ([RaananW](https://github.com/RaananW))
-- New NPM package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
-- A new HD-Toggler button allows setting a better hardware scaling rate ([RaananW](https://github.com/RaananW))
-- An initial support for WebVR is implemented ([RaananW](https://github.com/RaananW))
-- It is now possible to choose the element that goes fullscreen in the default viewer ([RaananW](https://github.com/RaananW))
-- The default viewer has a plugin system with which new buttons can be added externally ([RaananW](https://github.com/RaananW))
-- The extended configuration is now the default when not providing the "extended" parameter ([RaananW](https://github.com/RaananW))
-- viewer.updateConfiguration also accepts a URL to download configuration remotely ([RaananW](https://github.com/RaananW))
-- Viewer supports 3D printing on windows 10 ([RaananW](https://github.com/RaananW))
-- The viewer's environment map is using the new .env feature ([RaananW](https://github.com/RaananW))
-
-### Materials Library
-
-- Added ```unlit``` mode to lava material ([sebavan](http://www.github.com/sebavan))
-
-### Documentation
-
-- Added all code comments for GUI
-
-## Bug fixes
-
-- VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
-- RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
-- SceneSerializer.SerializeMesh now serializes all materials kinds (not only StandardMaterial) ([julien-moreau](https://github.com/julien-moreau))
-- WindowsMotionController's trackpad field will be updated prior to it's onTrackpadChangedObservable event ([TrevorDev](https://github.com/TrevorDev))
-- VR experience helper's controllers will not fire pointer events when laser's are disabled, instead the camera ray pointer event will be used ([TrevorDev](https://github.com/TrevorDev))
-- Node's setParent(node.parent) will no longer throw an exception when parent is undefined and will behave the same as setParent(null) ([TrevorDev](https://github.com/TrevorDev))
-- Mesh.MergeMeshes flips triangles on meshes with negative scaling ([SvenFrankson](http://svenfrankson.com))
-- Avoid firing button events multiple times when calling vrController.attachMesh() ([TrevorDev](https://github.com/TrevorDev))
-- Parse geometry when load binary mesh ([SinhNQ](https://github.com/quocsinh))
-- Removing observers during observable notify should not skip over valid observers ([TrevorDev](https://github.com/TrevorDev))
-- Initializing gamepadManager should register the gamepad update events ([TrevorDev](https://github.com/TrevorDev))
-- Do not generate mipmaps for RawCubeTexture if OES_texture_float_linear and/or EXT_color_buffer_float extensions are not supported ([PeapBoy](https://github.com/NicolasBuecher))
-- Do not modify passed camera array parameter when creating a default pipeline ([TrevorDev](https://github.com/TrevorDev))
-- Fixed issue where gaze trackers were appearing even after leaving VR ([atulyar](https://github.com/atulyar))
-- AdvancedDynamicTexture should not overwrite skipOnPointerObservable to false ([TrevorDev](https://github.com/TrevorDev))
-- Fixed issue where VRExperienceHelper.onExitingVR observable was being fired twice ([atulyar](https://github.com/atulyar))
-- Avoid firing onExitingVR observable multiple times when calling exitVR() and add observables to Viewer that can be used instead of the ones in VRExperienceHelper ([atulyar](https://github.com/atulyar))
-- GizmoManager should hide existing gizmos if a non-attachable mesh is selected ([TrevorDev](https://github.com/TrevorDev))
-- Ignore isPickable = false for vr ray casting if the mesh's name matches the specified floorMeshName to maintain backwards compatability ([TrevorDev](https://github.com/TrevorDev))
-- Fix File Loading if hosted from `file:`-Protocol ([ltetzlaff](https://github.com/ltetzlaff))
-- Do not throw error when updating a controller with no left stick ([TrevorDev](https://github.com/TrevorDev))
-- Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
-- Dispose existing gazeTrackers when setting a new one ([TrevorDev](https://github.com/TrevorDev))
-- Set missing parentId in Mesh.serialize() for instances ([julien-moreau](https://github.com/julien-moreau))
-- Do not modify pivot point when using bounding box gizmo or behaviors ([TrevorDev](https://github.com/TrevorDev))
-- GPUParticleSystem does not get stuck in burst loop when stopped and started ([TrevorDev](https://github.com/TrevorDev))
-- trackPosition:false not working in webVRCamera ([TrevorDev](https://github.com/TrevorDev))
-- Spring Joint could not be removed ([TrevorDev](https://github.com/TrevorDev))
-- Sometimes duplicate controller models are loaded in VR ([TrevorDev](https://github.com/TrevorDev))
-
-### Core Engine
-
-- Fixed ```shadowEnabled``` property on lights. Shadows are not visible anymore when disabled ([sebavan](http://www.github.com/sebavan))
-- Physics `unregisterOnPhysicsCollide` didn't remove callback correctly [#4291](https://github.com/BabylonJS/Babylon.js/issues/4291) ([RaananW](https://github.com/RaananW))
-- Added missing getter and setter for global exposure in ColorCurves ([RaananW](https://github.com/RaananW))
-- Fixed an issue with view matrix when `ArcRotateCamera` was used with collisions ([Deltakosh](https://github.com/deltakosh))
-- Fixed a bug with setting `unlit` on `PBRMaterial` after the material is ready (Wrong dirty flags) ([bghgary](http://www.github.com/bghgary))
-- Fixed `HighlightLayer` support on browsers not supporting HalfFloat ([sebavan](http://www.github.com/sebavan))
-- Fixed support for R and RG texture formats ([sebavan](http://www.github.com/sebavan))
-- Fixed `updatable` parameter setting in the SPS ([jerome](https://github.com/jbousquie))
-- Angular and linear velocity were using the wrong method to copy values to the physics engine ([RaananW](https://github.com/RaananW))
-- Fixed env texture generation in Byte Mode ([sebavan](http://www.github.com/sebavan))
-- Oimo.js now receives quaternion and not euler when a body is being constructed ([RaananW](https://github.com/RaananW))
-- Improving visual quality on SSAO2 shader ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fixed a bug where changing the sample count on `PostProcess` would not update the WebGL Texture ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fixed multi camera support in defaultRenderingPipeline depth of field ([sebavan](http://www.github.com/sebavan))
-
-### Viewer
-
-- Fix Navbar Interaction on Mozilla/Firefox ([SzeyinLee](https://github.com/SzeyinLee))
-- Fix Animation Slider Interaction on Mozilla/Firefox ([sebavan](http://www.github.com/sebavan))
-- Fix Animation Slider Clickable area size Cross Plat ([sebavan](http://www.github.com/sebavan))
-- Ground material didn't take the default main color is no material definition was provided ([RaananW](https://github.com/RaananW))
-- Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
-- It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
-- Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
-- Animation navbar now updates correctly when a new model is loaded [#4441](https://github.com/BabylonJS/Babylon.js/issues/4441) ([RaananW](https://github.com/RaananW))
-- Non-normalized meshes didn't center and focus correctly ([RaananW](https://github.com/RaananW))
-- Meshes with skeletons could have incorrect animations ([RaananW](https://github.com/RaananW))
-- Removed element IDs from viewer's templates to allow muitiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
-- Viewer is not using Engine.LastCreatedScene anymore, to support multiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
-- Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
-- Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
-- It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
-- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
-- Animation names with more than one word didn't work correctly ([RaananW](https://github.com/RaananW))
-
-### Loaders
-
-- STL Loader only supported binary downloads and no data: urls [#4473](https://github.com/BabylonJS/Babylon.js/issues/4473) ([RaananW](https://github.com/RaananW))
-- OBJ Loader is now an async loader [#4571](https://github.com/BabylonJS/Babylon.js/issues/4571) ([RaananW](https://github.com/RaananW))
-- GLTF Loader does not have texture conflicts on subsequent loads anymore [#5030](https://github.com/BabylonJS/Babylon.js/issues/5030) ([sebavan](http://www.github.com/sebavan))
-
-## Breaking changes
-
-- Fixing support for R and RG texture formats made us remove TextureFormat_R32F and TextureFormat_RG32F as they were mixing formats and types. Please, use the respective TextureFormat_R and TextureFormat_RG with the Float types ([sebavan](http://www.github.com/sebavan))
-- Replacing `scene.onRenderingGroupObservable` by `onBeforeRenderingGroupObservable` and `onAfterRenderingGroupObservable` to prevent the stage check ([sebavan](http://www.github.com/sebavan))
-- Replacing `IActiveMeshCandidateProvider` and the according scene setter by a set of custom predicates `scene.getActiveMeshCandidates`, `scene.getActiveSubMeshCandidates`, `scene.getIntersectingSubMeshCandidates` and `scene.getCollidingSubMeshCandidates` ([sebavan](http://www.github.com/sebavan)). This helps opening more customization to everybody.
+# 3.3.0
+
+## Major updates
+
+- GUI
+  - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
+  - New GUI control: [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
+  - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
+  -New GUI container [SelectionPanel](http://doc.babylonjs.com/how_to/selector) ([JohnK](https://github.com/BabylonJSGuide))
+- Gizmo Support ([TrevorDev](https://github.com/TrevorDev))
+  - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
+  - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
+  - Added attachToBoxBehavior to attach UI to a bounding box ([TrevorDev](https://github.com/TrevorDev))
+  - Gizmo manager's internal gizmos are now public ([TrevorDev](https://github.com/TrevorDev))
+  - Ability to customize meshes on gizmos ([TrevorDev](https://github.com/TrevorDev))
+  - Added ignoreChildren field to bounding box to save performance when using heavily nested meshes ([TrevorDev](https://github.com/TrevorDev))
+  - Add uniform scaling drag support to scale gizmo ([TrevorDev](https://github.com/TrevorDev))
+  - Support interacting with child elements ([TrevorDev](https://github.com/TrevorDev))
+  - BoundingBox gizmo support for including/excluding descendants when computing the bounding box ([TrevorDev](https://github.com/TrevorDev))
+- Particle system improvements ([Deltakosh](https://github.com/deltakosh))
+  - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
+  - Improved CPU particles rendering performance (up to x2 on low end devices)
+  - Added support for `isBillboardBased`. [Doc](http://doc.babylonjs.com/babylon101/particles#alignment)
+  - Added support for billboard mode. [Doc](https://doc.babylonjs.com/babylon101/particles#alignment)
+  - Added support for `minScaleX`, `minScaleY`, `maxScaleX`, `maxScaleY`. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
+  - Added support for `radiusRange` for sphere emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#sphere-emitter)
+  - Added support for `radiusRange` and `heightRange` for cone emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cone-emitter)
+  - Added new point emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#point-emitter)
+  - Added new hemispheric emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#hemispheric-emitter)
+  - Added support for `ParticleSystem.BLENDMODE_ADD` alpha mode. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-blending)
+  - Added support for color gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#particle-colors)
+  - Added support for pre-warming. [Doc](https://doc.babylonjs.com/babylon101/particles#pre-warming)
+  - Added support for `minInitialRotation` and `maxInitialRotation`. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
+  - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
+  - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
+  - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
+  - Added support for velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
+  - Added support for limit velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
+  - Added support for drag gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#drag-factor)
+  - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
+  - Added support for emit rate gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#emit-rate-over-time)
+  - Added support for ramp gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#ramp-gradients)
+  - Start size gradient support for particles. [Doc](http://doc.babylonjs.com/babylon101/particles#start-size-over-time) ([TrevorDev](https://github.com/TrevorDev))
+  - Attached sub emitters. [Doc](http://doc.babylonjs.com/how_to/sub_emitters) ([TrevorDev](https://github.com/TrevorDev))
+  - Cylinder particle emitter and constructor in baseParticle [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
+  - Added support for cylinder particle emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
+  - Added support for random start cell when using animated sprite sheets. [Doc](http://doc.babylonjs.com/how_to/animate)
+- Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
+- Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
+- Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
+- GUI and Inspector are now ES-Modules ([RaananW](https://github.com/RaananW))
+- Added support for noise procedural textures. [Doc](http://doc.babylonjs.com/how_to/how_to_use_procedural_textures#noise-procedural-texture) ([Deltakosh](https://github.com/deltakosh))
+- Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
+- Added Video Recorder [Documentation](https://doc.babylonjs.com/How_To/Render_Scene_on_a_Video) ([sebavan](http://www.github.com/sebavan))
+
+## Updates
+
+- Updated TypeScript version to new major 3.0.1 ([christopherstock](https://github.com/christopherstock))
+- All NPM packages have `latest` and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
+- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
+- Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
+
+### GUI
+- Added dead key support and before key add observable to InputText. [Doc](https://doc.babylonjs.com/how_to/gui#using-onbeforekeyaddobservable-for-extended-keyboard-layouts-and-input-masks)([theom](https://github.com/theom))
+- Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
+- New vertical mode for sliders in 2D GUI. [Demo](https://www.babylonjs-playground.com/#U9AC0N#53) ([Saket Saurabh](https://github.com/ssaket))
+- Added `isEnabled` and `disabledColor` property to Gui Control ([barteq100](https://github.com/barteq100))
+- Added support for connecting multiple InputText controls to VirtualKeyboard and can disconnect individual InputTexts. ([brian Zinn](https://github.com/brianzinn))
+
+### Core Engine
+
+- Improved the way world matrices were computed ([Deltakosh](https://github.com/deltakosh))
+- Added `scene.rootNodes` to track root nodes (ie. nodes with no parent) ([Deltakosh](https://github.com/deltakosh))
+- Added `scene.pickSpriteWithRay` function ([Deltakosh](https://github.com/deltakosh))
+- Added support for multiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
+- Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
+- Added new `BoundingInfo.scale()` function to let users control the size of the bounding info ([Deltakosh](https://github.com/deltakosh))
+- Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))
+- Added the choice of [forming a closed loop](http://doc.babylonjs.com/how_to/how_to_use_curve3#catmull-rom-spline) to the catmull-rom-spline curve3 ([johnk](https://github.com/babylonjsguide))
+- Added support for specifying the center of rotation to textures ([bghgary](http://www.github.com/bghgary))
+- Added webVR support for Oculus Go ([TrevorDev](https://github.com/TrevorDev))
+- Added ability to not generate polynomials harmonics upon prefiltered texture creation ([sebavan](http://www.github.com/sebavan))
+- Added predicate function to customize the list of mesh included in the computation of bounding vectors in the ```getHierarchyBoundingVectors``` method ([sebavan](http://www.github.com/sebavan))
+- Added webVR constructor options: disable laser pointer toggle, teleportation floor meshes ([TrevorDev](https://github.com/TrevorDev))
+- Get a root mesh from an asset container, load a mesh from a file with a single string url ([TrevorDev](https://github.com/TrevorDev))
+- UtilityLayer class to render another scene as a layer on top of an existing scene ([TrevorDev](https://github.com/TrevorDev))
+- AnimationGroup has now onAnimationGroupEnd observable ([RaananW](https://github.com/RaananW))
+- New `serialize` and `Parse` functions to serialize and parse all procedural textures from the Procedural Textures Library ([julien-moreau](https://github.com/julien-moreau))
+- Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
+- AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
+- Added sprite isVisible field ([TrevorDev](https://github.com/TrevorDev))
+- EnvironmentHelper will recreate ground and skybox meshes if force-disposed ([RaananW](https://github.com/RaananW))
+- Added viewport caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
+- Added unpackFlipY caching mechanism in engine ([sebavan](http://www.github.com/sebavan))
+- Added rebind optimization of video texture ([sebavan](http://www.github.com/sebavan))
+- Fix Background Material effect caching ([sebavan](http://www.github.com/sebavan))
+- Prevent texture ```getSize``` to generate garbage collection ([sebavan](http://www.github.com/sebavan))
+- Prevent ```lodGenerationScale``` and ```lodGenerationOffset``` to force rebind ([sebavan](http://www.github.com/sebavan))
+- Added poster property on VideoTexture ([sebavan](http://www.github.com/sebavan))
+- Added ```onUserActionRequestedObservable``` to workaround and detect autoplay video policy restriction on VideoTexture ([sebavan](http://www.github.com/sebavan))
+- `Sound` now accepts `MediaStream` as source to enable easier WebAudio and WebRTC integrations ([menduz](https://github.com/menduz))
+- Vector x, y and z constructor parameters are now optional and default to 0 ([TrevorDev](https://github.com/TrevorDev))
+- Added and removed camera methods in the default pipeline ([TrevorDev](https://github.com/TrevorDev))
+- Added internal texture `format` support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
+- Added canvas toBlob polyfill in tools ([sebavan](http://www.github.com/sebavan))
+- Added `RawCubeTexture` class with RGBD and mipmap support ([bghgary](http://www.github.com/bghgary))
+- Added effect layer per rendering group addressing [Issue 4463](https://github.com/BabylonJS/Babylon.js/issues/4463) ([sebavan](http://www.github.com/sebavan))
+- Added predicate function `targetMask` argument to `scene.beginWeightedAnimation`, `scene.beginAnimation`, `scene.stopAnimation`, and `animatable.stop` to allow for selective application of animations.  ([fmmoret](http://github.com/fmmoret))
+- Oculus GO and GearVR 3dof controllers will now rotate with the user's head if they turn around in their room ([TrevorDev](https://github.com/TrevorDev))
+- Added onPoseUpdatedFromDeviceObservable to webVRCamera to detect when the camera's pose has been updated ([TrevorDev](https://github.com/TrevorDev))
+- Added gltf light falloff [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added falloff type per light to prevent material only inconsistencies [Issue 4148](https://github.com/BabylonJS/Babylon.js/issues/4148) ([sebavan](http://www.github.com/sebavan))
+- Added WeightedSound; selects one from many Sounds with random weight for playback. ([najadojo](https://github.com/najadojo))
+- Added HDR support to ReflectionProbe ([Deltakosh](https://github.com/deltakosh))
+- Added ACES ToneMapping to the image processing to help getting more parity with other engines ([sebavan](http://www.github.com/sebavan))
+- Added Image Processing to the particle system to allow consistency in one pass forward rendering scenes ([sebavan](http://www.github.com/sebavan))
+- Added Video Recorder [Issue 4708](https://github.com/BabylonJS/Babylon.js/issues/4708) ([sebavan](http://www.github.com/sebavan))
+- Added support for main WebGL2 texture formats ([PeapBoy](https://github.com/NicolasBuecher))
+- Added fadeInOutBehavior and tooltipText for holographic buttons ([TrevorDev](https://github.com/TrevorDev))
+- StartDrag method added to pointerDragBehavior to simulate the start of a drag ([TrevorDev](https://github.com/TrevorDev))
+- Added EdgesLineRenderer to address [#4919](https://github.com/BabylonJS/Babylon.js/pull/4919) ([barteq100](https://github.com/barteq100))
+- Added ```ambientTextureImpactOnAnalyticalLights``` in PBRMaterial to allow fine grained control of the AmbientTexture on the analytical diffuse light ([sebavan](http://www.github.com/sebavan))
+- BoundingBoxGizmo scalePivot field that can be used to always scale objects from the bottom ([TrevorDev](https://github.com/TrevorDev))
+- Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
+- Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
+- Improved performance of cached nodes but ensuring parent always updates cache. This removes failed isSynchronized test that meant computeWorldMatrix would always have to rebuild. On large scenes this could double framerate. ([Bolloxim](https://github.com/Bolloxim))
+- Added FXAA and MSAA support to the StandardRenderingPipeline ([julien-moreau](https://github.com/julien-moreau))
+- Make teleportCamera public in VR experience helper ([TrevorDev](https://github.com/TrevorDev))
+
+
+### glTF Loader
+
+- Added support for KHR_texture_transform ([bghgary](http://www.github.com/bghgary))
+- Added `onNodeLODsLoadedObservable` and `onMaterialLODsLoadedObservable` to MSFT_lod loader extension ([bghgary](http://www.github.com/bghgary))
+- Added glTF loader settings to the GLTF tab in the debug layer ([bghgary](http://www.github.com/bghgary))
+- Added debug logging and performance counters ([bghgary](http://www.github.com/bghgary))
+- Added support for EXT_lights_imageBased ([bghgary](http://www.github.com/bghgary))
+- Added support for MSFT_audio_emitter ([najadojo](http://www.github.com/najadojo))
+- Added support for custom loader extensions ([bghgary](http://www.github.com/bghgary))
+
+### glTF Serializer
+- Added support for exporting the scale, rotation and offset texture properties ([kcoley](http://www.github.com/kcoley))
+
+### Viewer
+
+- No fullscreen button on small devices ([RaananW](https://github.com/RaananW))
+- Nav-Bar is now displayed on fullscreen per default ([RaananW](https://github.com/RaananW))
+- Viewer configuration supports deprecated values using the new configurationCompatibility processor  ([RaananW](https://github.com/RaananW))
+- Shadows will only render while models are entering the scene or animating ([RaananW](https://github.com/RaananW))
+- Support for model drag and drop onto the canvas ([RaananW](https://github.com/RaananW))
+- New lab feature - global light rotation [#4347](https://github.com/BabylonJS/Babylon.js/issues/4347) ([RaananW](https://github.com/RaananW))
+- New NPM package - babylonjs-viewer-assets, to separate the binary assets and the code of the viewer ([RaananW](https://github.com/RaananW))
+- A new HD-Toggler button allows setting a better hardware scaling rate ([RaananW](https://github.com/RaananW))
+- An initial support for WebVR is implemented ([RaananW](https://github.com/RaananW))
+- It is now possible to choose the element that goes fullscreen in the default viewer ([RaananW](https://github.com/RaananW))
+- The default viewer has a plugin system with which new buttons can be added externally ([RaananW](https://github.com/RaananW))
+- The extended configuration is now the default when not providing the "extended" parameter ([RaananW](https://github.com/RaananW))
+- viewer.updateConfiguration also accepts a URL to download configuration remotely ([RaananW](https://github.com/RaananW))
+- Viewer supports 3D printing on windows 10 ([RaananW](https://github.com/RaananW))
+- The viewer's environment map is using the new .env feature ([RaananW](https://github.com/RaananW))
+
+### Materials Library
+
+- Added ```unlit``` mode to lava material ([sebavan](http://www.github.com/sebavan))
+
+### Documentation
+
+- Added all code comments for GUI
+
+## Bug fixes
+
+- VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
+- RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
+- SceneSerializer.SerializeMesh now serializes all materials kinds (not only StandardMaterial) ([julien-moreau](https://github.com/julien-moreau))
+- WindowsMotionController's trackpad field will be updated prior to it's onTrackpadChangedObservable event ([TrevorDev](https://github.com/TrevorDev))
+- VR experience helper's controllers will not fire pointer events when laser's are disabled, instead the camera ray pointer event will be used ([TrevorDev](https://github.com/TrevorDev))
+- Node's setParent(node.parent) will no longer throw an exception when parent is undefined and will behave the same as setParent(null) ([TrevorDev](https://github.com/TrevorDev))
+- Mesh.MergeMeshes flips triangles on meshes with negative scaling ([SvenFrankson](http://svenfrankson.com))
+- Avoid firing button events multiple times when calling vrController.attachMesh() ([TrevorDev](https://github.com/TrevorDev))
+- Parse geometry when load binary mesh ([SinhNQ](https://github.com/quocsinh))
+- Removing observers during observable notify should not skip over valid observers ([TrevorDev](https://github.com/TrevorDev))
+- Initializing gamepadManager should register the gamepad update events ([TrevorDev](https://github.com/TrevorDev))
+- Do not generate mipmaps for RawCubeTexture if OES_texture_float_linear and/or EXT_color_buffer_float extensions are not supported ([PeapBoy](https://github.com/NicolasBuecher))
+- Do not modify passed camera array parameter when creating a default pipeline ([TrevorDev](https://github.com/TrevorDev))
+- Fixed issue where gaze trackers were appearing even after leaving VR ([atulyar](https://github.com/atulyar))
+- AdvancedDynamicTexture should not overwrite skipOnPointerObservable to false ([TrevorDev](https://github.com/TrevorDev))
+- Fixed issue where VRExperienceHelper.onExitingVR observable was being fired twice ([atulyar](https://github.com/atulyar))
+- Avoid firing onExitingVR observable multiple times when calling exitVR() and add observables to Viewer that can be used instead of the ones in VRExperienceHelper ([atulyar](https://github.com/atulyar))
+- GizmoManager should hide existing gizmos if a non-attachable mesh is selected ([TrevorDev](https://github.com/TrevorDev))
+- Ignore isPickable = false for vr ray casting if the mesh's name matches the specified floorMeshName to maintain backwards compatability ([TrevorDev](https://github.com/TrevorDev))
+- Fix File Loading if hosted from `file:`-Protocol ([ltetzlaff](https://github.com/ltetzlaff))
+- Do not throw error when updating a controller with no left stick ([TrevorDev](https://github.com/TrevorDev))
+- Exiting VR can result in messed up view ([TrevorDev](https://github.com/TrevorDev))
+- Dispose existing gazeTrackers when setting a new one ([TrevorDev](https://github.com/TrevorDev))
+- Set missing parentId in Mesh.serialize() for instances ([julien-moreau](https://github.com/julien-moreau))
+- Do not modify pivot point when using bounding box gizmo or behaviors ([TrevorDev](https://github.com/TrevorDev))
+- GPUParticleSystem does not get stuck in burst loop when stopped and started ([TrevorDev](https://github.com/TrevorDev))
+- trackPosition:false not working in webVRCamera ([TrevorDev](https://github.com/TrevorDev))
+- Spring Joint could not be removed ([TrevorDev](https://github.com/TrevorDev))
+- Sometimes duplicate controller models are loaded in VR ([TrevorDev](https://github.com/TrevorDev))
+
+### Core Engine
+
+- Fixed ```shadowEnabled``` property on lights. Shadows are not visible anymore when disabled ([sebavan](http://www.github.com/sebavan))
+- Physics `unregisterOnPhysicsCollide` didn't remove callback correctly [#4291](https://github.com/BabylonJS/Babylon.js/issues/4291) ([RaananW](https://github.com/RaananW))
+- Added missing getter and setter for global exposure in ColorCurves ([RaananW](https://github.com/RaananW))
+- Fixed an issue with view matrix when `ArcRotateCamera` was used with collisions ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with setting `unlit` on `PBRMaterial` after the material is ready (Wrong dirty flags) ([bghgary](http://www.github.com/bghgary))
+- Fixed `HighlightLayer` support on browsers not supporting HalfFloat ([sebavan](http://www.github.com/sebavan))
+- Fixed support for R and RG texture formats ([sebavan](http://www.github.com/sebavan))
+- Fixed `updatable` parameter setting in the SPS ([jerome](https://github.com/jbousquie))
+- Angular and linear velocity were using the wrong method to copy values to the physics engine ([RaananW](https://github.com/RaananW))
+- Fixed env texture generation in Byte Mode ([sebavan](http://www.github.com/sebavan))
+- Oimo.js now receives quaternion and not euler when a body is being constructed ([RaananW](https://github.com/RaananW))
+- Improving visual quality on SSAO2 shader ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fixed a bug where changing the sample count on `PostProcess` would not update the WebGL Texture ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fixed multi camera support in defaultRenderingPipeline depth of field ([sebavan](http://www.github.com/sebavan))
+
+### Viewer
+
+- Fix Navbar Interaction on Mozilla/Firefox ([SzeyinLee](https://github.com/SzeyinLee))
+- Fix Animation Slider Interaction on Mozilla/Firefox ([sebavan](http://www.github.com/sebavan))
+- Fix Animation Slider Clickable area size Cross Plat ([sebavan](http://www.github.com/sebavan))
+- Ground material didn't take the default main color is no material definition was provided ([RaananW](https://github.com/RaananW))
+- Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
+- It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
+- Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
+- Animation navbar now updates correctly when a new model is loaded [#4441](https://github.com/BabylonJS/Babylon.js/issues/4441) ([RaananW](https://github.com/RaananW))
+- Non-normalized meshes didn't center and focus correctly ([RaananW](https://github.com/RaananW))
+- Meshes with skeletons could have incorrect animations ([RaananW](https://github.com/RaananW))
+- Removed element IDs from viewer's templates to allow muitiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
+- Viewer is not using Engine.LastCreatedScene anymore, to support multiple viewers in a single page [#4500](https://github.com/BabylonJS/Babylon.js/issues/4500) ([RaananW](https://github.com/RaananW))
+- Template location was ignored if html was defined ([RaananW](https://github.com/RaananW))
+- Drag and Drop only worked if a model was already loaded before ([RaananW](https://github.com/RaananW))
+- It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
+- Button texts were truncated incorrectly ([RaananW](https://github.com/RaananW))
+- Animation names with more than one word didn't work correctly ([RaananW](https://github.com/RaananW))
+
+### Loaders
+
+- STL Loader only supported binary downloads and no data: urls [#4473](https://github.com/BabylonJS/Babylon.js/issues/4473) ([RaananW](https://github.com/RaananW))
+- OBJ Loader is now an async loader [#4571](https://github.com/BabylonJS/Babylon.js/issues/4571) ([RaananW](https://github.com/RaananW))
+- GLTF Loader does not have texture conflicts on subsequent loads anymore [#5030](https://github.com/BabylonJS/Babylon.js/issues/5030) ([sebavan](http://www.github.com/sebavan))
+
+## Breaking changes
+
+- Fixing support for R and RG texture formats made us remove TextureFormat_R32F and TextureFormat_RG32F as they were mixing formats and types. Please, use the respective TextureFormat_R and TextureFormat_RG with the Float types ([sebavan](http://www.github.com/sebavan))
+- Replacing `scene.onRenderingGroupObservable` by `onBeforeRenderingGroupObservable` and `onAfterRenderingGroupObservable` to prevent the stage check ([sebavan](http://www.github.com/sebavan))
+- Replacing `IActiveMeshCandidateProvider` and the according scene setter by a set of custom predicates `scene.getActiveMeshCandidates`, `scene.getActiveSubMeshCandidates`, `scene.getIntersectingSubMeshCandidates` and `scene.getCollidingSubMeshCandidates` ([sebavan](http://www.github.com/sebavan)). This helps opening more customization to everybody.

+ 110 - 0
serializers/src/glTF/2.0/Extensions/KHR_texture_transform.ts

@@ -0,0 +1,110 @@
+/// <reference path="../../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+
+module BABYLON.GLTF2.Exporter.Extensions {
+    const NAME = "KHR_texture_transform";
+
+    /**
+     * Interface for handling KHR texture transform
+     * @hidden
+     */
+    interface IKHRTextureTransform {
+        offset?: number[];
+        rotation?: number;
+        scale?: number[];
+        texCoord?: number;
+    }
+
+    /**
+     * @hidden
+     */
+    export class KHR_texture_transform implements IGLTFExporterExtension {
+        /** Name of this extension */
+        public readonly name = NAME;
+
+        /** Defines whether this extension is enabled */
+        public enabled = true;
+
+        /** Defines whether this extension is required */
+        public required = false;
+
+        /** Reference to the glTF exporter */
+        private _exporter: _Exporter;
+
+        constructor(exporter: _Exporter) {
+            this._exporter = exporter;
+        }
+
+        public dispose() {
+            delete this._exporter;
+        }
+
+        public preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>> {
+            return new Promise((resolve, reject) => {
+                const texture_transform_extension: IKHRTextureTransform = {};
+
+                if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
+                    texture_transform_extension.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
+                }
+
+                if (babylonTexture.uScale !== 1 || babylonTexture.vScale !== 1) {
+                    texture_transform_extension.scale = [babylonTexture.uScale, babylonTexture.vScale];
+                }
+
+                if (babylonTexture.wAng !== 0) {
+                    texture_transform_extension.rotation = babylonTexture.wAng;
+                }
+
+                if (!Object.keys(texture_transform_extension).length) {
+                    resolve(babylonTexture);
+                }
+
+                const scale = texture_transform_extension.scale ? new Vector2(texture_transform_extension.scale[0], texture_transform_extension.scale[1]) : Vector2.One();
+                const rotation = texture_transform_extension.rotation != null ? texture_transform_extension.rotation : 0;
+                const offset = texture_transform_extension.offset ? new Vector2(texture_transform_extension.offset[0], texture_transform_extension.offset[1]) : Vector2.Zero();
+                const scene = babylonTexture.getScene();
+                if (!scene) {
+                    reject(`${context}: "scene" is not defined for Babylon texture ${babylonTexture.name}!`);
+                }
+                else {
+                    this.textureTransformTextureAsync(babylonTexture, offset, rotation, scale, scene).then(texture => {
+                        resolve(texture as Texture);
+                    });
+                }
+            });
+        }
+
+        /**
+         * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
+         * @param babylonTexture 
+         * @param offset 
+         * @param rotation 
+         * @param scale 
+         * @param scene 
+         */
+        public textureTransformTextureAsync(babylonTexture: Texture, offset: Vector2, rotation: number, scale: Vector2, scene: Scene): Promise<BaseTexture> {
+            return new Promise((resolve, reject) => {
+                const proceduralTexture = new ProceduralTexture(`${babylonTexture.name}`, babylonTexture.getSize(), "textureTransform", scene);
+                if (!proceduralTexture) {
+                    Tools.Log(`Cannot create procedural texture for ${babylonTexture.name}!`);
+                    resolve(babylonTexture);
+                }
+
+                proceduralTexture.setTexture("textureSampler", babylonTexture);
+                proceduralTexture.setMatrix("textureTransformMat", babylonTexture.getTextureMatrix());
+
+                // isReady trigger creation of effect if it doesnt exist yet
+                if(proceduralTexture.isReady()){
+                    proceduralTexture.render();
+                    resolve(proceduralTexture)
+                }else{
+                    (proceduralTexture as any)._effect.onCompileObservable.add(() => {
+                        proceduralTexture.render();
+                        resolve(proceduralTexture);
+                    });
+                }
+            });
+        }
+    }
+
+    _Exporter.RegisterExtension(NAME, exporter => new KHR_texture_transform(exporter));
+}

+ 1 - 1
serializers/src/glTF/2.0/babylon.glTFAnimation.ts

@@ -1,6 +1,6 @@
 /// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
-module BABYLON.GLTF2 {
+module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      * Interface to store animation data.

+ 206 - 90
serializers/src/glTF/2.0/babylon.glTFExporter.ts

@@ -1,6 +1,6 @@
 /// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
-module BABYLON.GLTF2 {
+module BABYLON.GLTF2.Exporter {
     /** 
      * Utility interface for storing vertex attribute data
      * @hidden
@@ -32,11 +32,11 @@ module BABYLON.GLTF2 {
         /**
          * Stores all generated buffer views, which represents views into the main glTF buffer data
          */
-        private _bufferViews: IBufferView[];
+        public _bufferViews: IBufferView[];
         /**
          * Stores all the generated accessors, which is used for accessing the data within the buffer views in glTF
          */
-        private _accessors: IAccessor[];
+        public _accessors: IAccessor[];
         /**
          * Stores all the generated nodes, which contains transform and/or mesh information per node
          */
@@ -115,7 +115,60 @@ module BABYLON.GLTF2 {
 
         private _localEngine: Engine;
 
-        private _glTFMaterialExporter: _GLTFMaterialExporter;
+        public _glTFMaterialExporter: _GLTFMaterialExporter;
+
+        private _extensions: { [name: string]: IGLTFExporterExtension } = {};
+
+        private _extensionsUsed: string[];
+        private _extensionsRequired: string[];
+
+        private static _ExtensionNames = new Array<string>();
+        private static _ExtensionFactories: { [name: string]: (exporter: _Exporter) => IGLTFExporterExtension } = {};
+
+        private _applyExtensions<T>(property: any, actionAsync: (extension: IGLTFExporterExtension) => Nullable<T> | undefined): Nullable<T> {
+            for (const name of _Exporter._ExtensionNames) {
+                const extension = this._extensions[name];
+                if (extension.enabled) {
+                    const exporterProperty = property as any;
+                    exporterProperty._activeLoaderExtensions = exporterProperty._activeLoaderExtensions || {};
+                    const activeLoaderExtensions = exporterProperty._activeLoaderExtensions;
+                    if (!activeLoaderExtensions[name]) {
+                        activeLoaderExtensions[name] = true;
+
+                        try {
+                            const result = actionAsync(extension);
+                            if (result) {
+                                return result;
+                            }
+                        }
+                        finally {
+                            delete activeLoaderExtensions[name];
+                            delete exporterProperty._activeLoaderExtensions;
+                        }
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        public _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>> {
+            return this._applyExtensions(babylonTexture, extension => extension.preExportTextureAsync && extension.preExportTextureAsync(context, babylonTexture, mimeType));
+        }
+        
+        public _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>> {
+            return this._applyExtensions(meshPrimitive, extension => extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, meshPrimitive, babylonSubMesh, binaryWriter));
+        }
+
+        /**
+         * Load glTF serializer extensions
+         */
+        private _loadExtensions(): void {
+            for (const name of _Exporter._ExtensionNames) {
+                const extension = _Exporter._ExtensionFactories[name](this);
+                this._extensions[name] = extension;
+            }
+        }
 
         /**
          * Creates a glTF Exporter instance, which can accept optional exporter options
@@ -124,6 +177,8 @@ module BABYLON.GLTF2 {
          */
         public constructor(babylonScene: Scene, options?: IExportOptions) {
             this._asset = { generator: "BabylonJS", version: "2.0" };
+            this._extensionsUsed = [];
+            this._extensionsRequired = [];
             this._babylonScene = babylonScene;
             this._bufferViews = [];
             this._accessors = [];
@@ -143,6 +198,40 @@ module BABYLON.GLTF2 {
             this._animationSampleRate = _options.animationSampleRate ? _options.animationSampleRate : 1 / 60;
 
             this._glTFMaterialExporter = new _GLTFMaterialExporter(this);
+            this._loadExtensions();
+        }
+
+        /**
+         * Registers a glTF exporter extension
+         * @param name Name of the extension to export
+         * @param factory The factory function that creates the exporter extension
+         */
+        public static RegisterExtension(name: string, factory: (exporter: _Exporter) => IGLTFExporterExtension): void {
+            if (_Exporter.UnregisterExtension(name)) {
+                Tools.Warn(`Extension with the name ${name} already exists`);
+            }
+
+            _Exporter._ExtensionFactories[name] = factory;
+            _Exporter._ExtensionNames.push(name);
+        }
+
+        /**
+         * Un-registers an exporter extension
+         * @param name The name fo the exporter extension
+         * @returns A boolean indicating whether the extension has been un-registered
+         */
+        public static UnregisterExtension(name: string): boolean {
+            if (!_Exporter._ExtensionFactories[name]) {
+                return false;
+            }
+            delete _Exporter._ExtensionFactories[name];
+
+            const index = _Exporter._ExtensionNames.indexOf(name);
+            if (index !== -1) {
+                _Exporter._ExtensionNames.splice(index, 1);
+            }
+
+            return true;
         }
 
         /**
@@ -300,7 +389,6 @@ module BABYLON.GLTF2 {
             else {
                 Tools.Warn(`reorderTriangleFillMode: Vertex Buffer Kind ${vertexBufferKind} not present!`);
             }
-
         }
 
         /**
@@ -447,8 +535,7 @@ module BABYLON.GLTF2 {
                         }
                     }
                     else {
-                        
-                        _GLTFUtilities._GetRightHandedVector4FromRef(vertex);   
+                        _GLTFUtilities._GetRightHandedVector4FromRef(vertex);
                     }
                 }
                 if (vertexAttributeKind === VertexBuffer.NormalKind) {
@@ -473,7 +560,7 @@ module BABYLON.GLTF2 {
          * @param binaryWriter The buffer to write the binary data to
          * @param indices Used to specify the order of the vertex data
          */
-        private writeAttributeData(vertexBufferKind: string, meshAttributeArray: FloatArray, byteStride: number, binaryWriter: _BinaryWriter) {
+        public writeAttributeData(vertexBufferKind: string, meshAttributeArray: FloatArray, byteStride: number, binaryWriter: _BinaryWriter) {
             const stride = byteStride / 4;
             let vertexAttributes: number[][] = [];
             let index: number;
@@ -560,6 +647,12 @@ module BABYLON.GLTF2 {
             let glTF: IGLTF = {
                 asset: this._asset
             };
+            if (this._extensionsUsed && this._extensionsUsed.length) {
+                glTF.extensionsUsed = this._extensionsUsed;
+            }
+            if (this._extensionsRequired && this._extensionsRequired.length) {
+                glTF.extensionsRequired = this._extensionsRequired;
+            }
             if (buffer.byteLength) {
                 glTF.buffers = [buffer];
             }
@@ -771,8 +864,6 @@ module BABYLON.GLTF2 {
                     this._localEngine.dispose();
                 }
 
-                
-
                 return container;
             });
         }
@@ -783,7 +874,7 @@ module BABYLON.GLTF2 {
          * @param babylonTransformNode Babylon mesh used as the source for the transformation data
          */
         private setNodeTransformation(node: INode, babylonTransformNode: TransformNode): void {
-            if (!babylonTransformNode.getPivotPoint().equalsToFloats(0,0,0)) {
+            if (!babylonTransformNode.getPivotPoint().equalsToFloats(0, 0, 0)) {
                 BABYLON.Tools.Warn("Pivot points are not supported in the glTF serializer");
             }
             if (!babylonTransformNode.position.equalsToFloats(0, 0, 0)) {
@@ -942,7 +1033,8 @@ module BABYLON.GLTF2 {
          * @param babylonTransformNode Babylon mesh to get the primitive attribute data from
          * @param binaryWriter Buffer to write the attribute data to
          */
-        private setPrimitiveAttributes(mesh: IMesh, babylonTransformNode: TransformNode, binaryWriter: _BinaryWriter) {
+        private setPrimitiveAttributesAsync(mesh: IMesh, babylonTransformNode: TransformNode, binaryWriter: _BinaryWriter): Promise<void> {
+            let promises: Promise<IMeshPrimitive>[] = [];
             let bufferMesh: Nullable<Mesh> = null;
             let bufferView: IBufferView;
             let uvCoordsPresent: boolean;
@@ -1003,7 +1095,7 @@ module BABYLON.GLTF2 {
                     for (const submesh of bufferMesh.subMeshes) {
                         uvCoordsPresent = false;
                         let babylonMaterial = submesh.getMaterial() || bufferMesh.getScene().defaultMaterial;
-                        
+
                         let materialIndex: Nullable<number> = null;
                         if (babylonMaterial) {
                             if (bufferMesh instanceof LinesMesh) {
@@ -1108,9 +1200,17 @@ module BABYLON.GLTF2 {
 
                         }
                         mesh.primitives.push(meshPrimitive);
+
+                        const promise = this._extensionsPostExportMeshPrimitiveAsync("postExport", meshPrimitive, submesh, binaryWriter);
+                        if (promise) {
+                            promises.push();
+                        }
                     }
                 }
             }
+            return Promise.all(promises).then(() => {
+                /* do nothing */
+            });
         }
 
         /**
@@ -1127,50 +1227,55 @@ module BABYLON.GLTF2 {
             const nodes = [...babylonScene.transformNodes, ...babylonScene.meshes];
 
             return this._glTFMaterialExporter._convertMaterialsToGLTFAsync(babylonScene.materials, ImageMimeType.PNG, true).then(() => {
-                this._nodeMap = this.createNodeMapAndAnimations(babylonScene, nodes, this._shouldExportTransformNode, binaryWriter);
+                return this.createNodeMapAndAnimationsAsync(babylonScene, nodes, this._shouldExportTransformNode, binaryWriter).then((nodeMap) => {
+                    this._nodeMap = nodeMap;
 
-                this._totalByteLength = binaryWriter.getByteOffset();
+                    this._totalByteLength = binaryWriter.getByteOffset();
+                    if (this._totalByteLength == undefined) {
+                        throw new Error("undefined byte length!");
+                    }
 
 
-                // Build Hierarchy with the node map.
-                for (let babylonTransformNode of nodes) {
-                    glTFNodeIndex = this._nodeMap[babylonTransformNode.uniqueId];
-                    if (glTFNodeIndex != null) {
-                        glTFNode = this._nodes[glTFNodeIndex];
-                        if (!babylonTransformNode.parent) {
-                            if (!this._shouldExportTransformNode(babylonTransformNode)) {
-                                Tools.Log("Omitting " + babylonTransformNode.name + " from scene.");
-                            }
-                            else {
-                                if (this._convertToRightHandedSystem) {
-                                    if (glTFNode.translation) {
-                                        glTFNode.translation[2] *= -1;
-                                        glTFNode.translation[0] *= -1;
-                                    }
-                                    glTFNode.rotation = glTFNode.rotation ? Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(glTFNode.rotation)).asArray() : (Quaternion.FromArray([0, 1, 0, 0])).asArray();
+                    // Build Hierarchy with the node map.
+                    for (let babylonTransformNode of nodes) {
+                        glTFNodeIndex = this._nodeMap[babylonTransformNode.uniqueId];
+                        if (glTFNodeIndex != null) {
+                            glTFNode = this._nodes[glTFNodeIndex];
+                            if (!babylonTransformNode.parent) {
+                                if (!this._shouldExportTransformNode(babylonTransformNode)) {
+                                    Tools.Log("Omitting " + babylonTransformNode.name + " from scene.");
                                 }
+                                else {
+                                    if (this._convertToRightHandedSystem) {
+                                        if (glTFNode.translation) {
+                                            glTFNode.translation[2] *= -1;
+                                            glTFNode.translation[0] *= -1;
+                                        }
+                                        glTFNode.rotation = glTFNode.rotation ? Quaternion.FromArray([0, 1, 0, 0]).multiply(Quaternion.FromArray(glTFNode.rotation)).asArray() : (Quaternion.FromArray([0, 1, 0, 0])).asArray();
+                                    }
 
-                                scene.nodes.push(glTFNodeIndex);
+                                    scene.nodes.push(glTFNodeIndex);
+                                }
                             }
-                        }
 
-                        directDescendents = babylonTransformNode.getDescendants(true);
-                        if (!glTFNode.children && directDescendents && directDescendents.length) {
-                            const children: number[] = [];
-                            for (let descendent of directDescendents) {
-                                if (this._nodeMap[descendent.uniqueId] != null) {
-                                    children.push(this._nodeMap[descendent.uniqueId]);
+                            directDescendents = babylonTransformNode.getDescendants(true);
+                            if (!glTFNode.children && directDescendents && directDescendents.length) {
+                                const children: number[] = [];
+                                for (let descendent of directDescendents) {
+                                    if (this._nodeMap[descendent.uniqueId] != null) {
+                                        children.push(this._nodeMap[descendent.uniqueId]);
+                                    }
+                                }
+                                if (children.length) {
+                                    glTFNode.children = children;
                                 }
-                            }
-                            if (children.length) {
-                                glTFNode.children = children;
                             }
                         }
+                    };
+                    if (scene.nodes.length) {
+                        this._scenes.push(scene);
                     }
-                };
-                if (scene.nodes.length) {
-                    this._scenes.push(scene);
-                }
+                });
             });
         }
 
@@ -1182,7 +1287,8 @@ module BABYLON.GLTF2 {
          * @param binaryWriter Buffer to write binary data to
          * @returns Node mapping of unique id to index
          */
-        private createNodeMapAndAnimations(babylonScene: Scene, nodes: TransformNode[], shouldExportTransformNode: (babylonTransformNode: TransformNode) => boolean, binaryWriter: _BinaryWriter): { [key: number]: number } {
+        private createNodeMapAndAnimationsAsync(babylonScene: Scene, nodes: TransformNode[], shouldExportTransformNode: (babylonTransformNode: TransformNode) => boolean, binaryWriter: _BinaryWriter): Promise<{ [key: number]: number }> {
+            let promiseChain =  Promise.resolve();
             const nodeMap: { [key: number]: number } = {};
             let nodeIndex: number;
             let runtimeGLTFAnimation: IAnimation = {
@@ -1191,42 +1297,45 @@ module BABYLON.GLTF2 {
                 samplers: []
             };
             let idleGLTFAnimations: IAnimation[] = [];
-            let node: INode;
 
             for (let babylonTransformNode of nodes) {
                 if (shouldExportTransformNode(babylonTransformNode)) {
-                    node = this.createNode(babylonTransformNode, binaryWriter);
-
-                    const directDescendents = babylonTransformNode.getDescendants(true, (node: Node) => {return (node instanceof TransformNode);});
-                    if (directDescendents.length || node.mesh != null) {
-                        this._nodes.push(node);
-                        nodeIndex = this._nodes.length - 1;
-                        nodeMap[babylonTransformNode.uniqueId] = nodeIndex;
-                    }
+                    promiseChain = promiseChain.then(() => {
+                        return  this.createNodeAsync(babylonTransformNode, binaryWriter).then((node) => {
+                            const directDescendents = babylonTransformNode.getDescendants(true, (node: Node) => { return (node instanceof TransformNode); });
+                            if (directDescendents.length || node.mesh != null) {
+                                this._nodes.push(node);
+                                nodeIndex = this._nodes.length - 1;
+                                nodeMap[babylonTransformNode.uniqueId] = nodeIndex;
+                            }
 
-                    if (!babylonScene.animationGroups.length && babylonTransformNode.animations.length) {
-                        _GLTFAnimation._CreateNodeAnimationFromTransformNodeAnimations(babylonTransformNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, this._nodes, binaryWriter, this._bufferViews, this._accessors, this._convertToRightHandedSystem, this._animationSampleRate);
-                    }
+                            if (!babylonScene.animationGroups.length && babylonTransformNode.animations.length) {
+                                _GLTFAnimation._CreateNodeAnimationFromTransformNodeAnimations(babylonTransformNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, this._nodes, binaryWriter, this._bufferViews, this._accessors, this._convertToRightHandedSystem, this._animationSampleRate);
+                            }
+                        });
+                    });
                 }
                 else {
                     `Excluding mesh ${babylonTransformNode.name}`;
                 }
             };
 
-            if (runtimeGLTFAnimation.channels.length && runtimeGLTFAnimation.samplers.length) {
-                this._animations.push(runtimeGLTFAnimation);
-            }
-            idleGLTFAnimations.forEach((idleGLTFAnimation) => {
-                if (idleGLTFAnimation.channels.length && idleGLTFAnimation.samplers.length) {
-                    this._animations.push(idleGLTFAnimation);
+            return promiseChain.then(() => {
+                if (runtimeGLTFAnimation.channels.length && runtimeGLTFAnimation.samplers.length) {
+                    this._animations.push(runtimeGLTFAnimation);
                 }
-            });
+                idleGLTFAnimations.forEach((idleGLTFAnimation) => {
+                    if (idleGLTFAnimation.channels.length && idleGLTFAnimation.samplers.length) {
+                        this._animations.push(idleGLTFAnimation);
+                    }
+                });
 
-            if (babylonScene.animationGroups.length) {
-                _GLTFAnimation._CreateNodeAnimationFromAnimationGroups(babylonScene, this._animations, nodeMap, this._nodes, binaryWriter, this._bufferViews, this._accessors, this._convertToRightHandedSystem, this._animationSampleRate);
-            }
+                if (babylonScene.animationGroups.length) {
+                    _GLTFAnimation._CreateNodeAnimationFromAnimationGroups(babylonScene, this._animations, nodeMap, this._nodes, binaryWriter, this._bufferViews, this._accessors, this._convertToRightHandedSystem, this._animationSampleRate);
+                }
 
-            return nodeMap;
+                return nodeMap;
+            });
         }
 
         /**
@@ -1235,26 +1344,29 @@ module BABYLON.GLTF2 {
          * @param binaryWriter Buffer for storing geometry data
          * @returns glTF node
          */
-        private createNode(babylonTransformNode: TransformNode, binaryWriter: _BinaryWriter): INode {
-            // create node to hold translation/rotation/scale and the mesh
-            const node: INode = {};
-            // create mesh
-            const mesh: IMesh = { primitives: [] };
-
-            if (babylonTransformNode.name) {
-                node.name = babylonTransformNode.name;
-            }
+        private createNodeAsync(babylonTransformNode: TransformNode, binaryWriter: _BinaryWriter): Promise<INode> {
+            return Promise.resolve().then(() => {
+                // create node to hold translation/rotation/scale and the mesh
+                const node: INode = {};
+                // create mesh
+                const mesh: IMesh = { primitives: [] };
+
+                if (babylonTransformNode.name) {
+                    node.name = babylonTransformNode.name;
+                }
 
-            // Set transformation
-            this.setNodeTransformation(node, babylonTransformNode);
-            this.setPrimitiveAttributes(mesh, babylonTransformNode, binaryWriter);
+                // Set transformation
+                this.setNodeTransformation(node, babylonTransformNode);
 
-            if (mesh.primitives.length) {
-                this._meshes.push(mesh);
-                node.mesh = this._meshes.length - 1;
-            }
+                return this.setPrimitiveAttributesAsync(mesh, babylonTransformNode, binaryWriter).then(() => {
+                    if (mesh.primitives.length) {
+                        this._meshes.push(mesh);
+                        node.mesh = this._meshes.length - 1;
+                    }
 
-            return node;
+                    return node;
+                });
+            });
         }
     }
 
@@ -1289,7 +1401,7 @@ module BABYLON.GLTF2 {
          * Resize the array buffer to the specified byte length
          * @param byteLength 
          */
-        private resizeBuffer(byteLength: number) {
+        private resizeBuffer(byteLength: number): ArrayBuffer {
             let newBuffer = new ArrayBuffer(byteLength);
             let oldUint8Array = new Uint8Array(this._arrayBuffer);
             let newUint8Array = new Uint8Array(newBuffer);
@@ -1298,20 +1410,24 @@ module BABYLON.GLTF2 {
             }
             this._arrayBuffer = newBuffer;
             this._dataView = new DataView(this._arrayBuffer);
+
+            return newBuffer;
         }
         /**
          * Get an array buffer with the length of the byte offset
          * @returns ArrayBuffer resized to the byte offset
          */
         public getArrayBuffer(): ArrayBuffer {
-            this.resizeBuffer(this.getByteOffset());
-            return this._arrayBuffer;
+            return this.resizeBuffer(this.getByteOffset());
         }
         /**
          * Get the byte offset of the array buffer
          * @returns byte offset
          */
         public getByteOffset(): number {
+            if (this._byteOffset == undefined) {
+                throw new Error("Byte offset is undefined!");
+            }
             return this._byteOffset;
         }
         /**

+ 35 - 0
serializers/src/glTF/2.0/babylon.glTFExporterExtension.ts

@@ -0,0 +1,35 @@
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
+
+module BABYLON.GLTF2.Exporter {
+    /**
+     * Interface for a glTF exporter extension
+     * @hidden
+     */
+    export interface IGLTFExporterExtension extends BABYLON.IGLTFExporterExtension, IDisposable {
+        /**
+         * Define this method to modify the default behavior before exporting a texture
+         * @param context The context when loading the asset
+         * @param babylonTexture The glTF texture info property
+         * @param mimeType The mime-type of the generated image
+         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+
+        /**
+         * Define this method to modify the default behavior when exporting texture info
+         * @param context The context when loading the asset
+         * @param meshPrimitive glTF mesh primitive
+         * @param babylonSubMesh Babylon submesh
+         * @param binaryWriter glTF serializer binary writer instance
+         */
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+
+
+    }
+}
+
+/**
+ * Defines the module for the built-in glTF 2.0 exporter extensions.
+ */
+module BABYLON.GLTF2.Extensions {
+}

+ 19 - 8
serializers/src/glTF/2.0/babylon.glTFMaterialExporter.ts

@@ -1,6 +1,6 @@
 /// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
-module BABYLON.GLTF2 {
+module BABYLON.GLTF2.Exporter {
     /** 
      * Interface for storing specular glossiness factors
      * @hidden
@@ -512,7 +512,7 @@ module BABYLON.GLTF2 {
                                 fileReader.readAsDataURL(blob);
                             }
                             else {
-                                reject("Failed to get blob from image canvas!");
+                                reject("gltfMaterialExporter: Failed to get blob from image canvas!");
                             }
                         });
                     }
@@ -1036,7 +1036,7 @@ module BABYLON.GLTF2 {
         private setMetallicRoughnessPbrMaterial(metallicRoughness: Nullable<_IPBRMetallicRoughness>, babylonPBRMaterial: PBRMaterial, glTFMaterial: IMaterial, glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void> {
             const materialMap = this._exporter._materialMap;
             const materials = this._exporter._materials;
-            let promises = [];
+            let promises = [];  
             if (metallicRoughness) {
                 let alphaMode: Nullable<MaterialAlphaMode> = null;
                 if (babylonPBRMaterial.transparencyMode != null) {
@@ -1135,12 +1135,23 @@ module BABYLON.GLTF2 {
          * Extracts a texture from a Babylon texture into file data and glTF data
          * @param babylonTexture Babylon texture to extract
          * @param mimeType Mime Type of the babylonTexture
-         * @param images Array of glTF images
-         * @param textures Array of glTF textures
-         * @param imageData map of image file name and data
          * @return glTF texture info, or null if the texture format is not supported
          */
-        private _exportTextureAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>> {
+        public _exportTextureAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>> {
+            const extensionPromise = this._exporter._extensionsPreExportTextureAsync("exporter", babylonTexture as Texture, mimeType);
+            if (!extensionPromise) {
+                return this._exportTextureInfoAsync(babylonTexture, mimeType);
+            }
+
+            return extensionPromise.then(texture => {
+                if (!texture) {
+                    return this._exportTextureInfoAsync(babylonTexture, mimeType);
+                }
+                return this._exportTextureInfoAsync(texture, mimeType);
+            });
+        }
+
+        public _exportTextureInfoAsync(babylonTexture: BaseTexture, mimeType: ImageMimeType): Promise<Nullable<ITextureInfo>> {
             return Promise.resolve().then(() => {
                 const textureUid = babylonTexture.uid;
                 if (textureUid in this._textureMap) {
@@ -1172,7 +1183,7 @@ module BABYLON.GLTF2 {
                     const size = babylonTexture.getSize();
 
                     return this._createBase64FromCanvasAsync(pixels, size.width, size.height, mimeType).then(base64Data => {
-                        const textureInfo = this._getTextureInfoFromBase64(base64Data, babylonTexture.name.replace(/\.\/|\/|\.\\|\\/g , "_"), mimeType, babylonTexture.coordinatesIndex, samplerIndex);
+                        const textureInfo = this._getTextureInfoFromBase64(base64Data, babylonTexture.name.replace(/\.\/|\/|\.\\|\\/g, "_"), mimeType, babylonTexture.coordinatesIndex, samplerIndex);
                         if (textureInfo) {
                             this._textureMap[textureUid] = textureInfo;
                         }

+ 33 - 4
serializers/src/glTF/2.0/babylon.glTFSerializer.ts

@@ -15,6 +15,11 @@ module BABYLON {
          * The sample rate to bake animation curves
          */
         animationSampleRate?: number;
+
+        /**
+         * Begin serialization without waiting for the scene to be ready
+         */
+        exportWithoutWaitingForScene?: boolean;
     };
 
     /**
@@ -32,11 +37,33 @@ module BABYLON {
         public static GLTFAsync(scene: Scene, filePrefix: string, options?: IExportOptions): Promise<GLTFData> {
             return scene.whenReadyAsync().then(() => {
                 const glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");
-                const gltfGenerator = new GLTF2._Exporter(scene, options);
+                const gltfGenerator = new GLTF2.Exporter._Exporter(scene, options);
                 return gltfGenerator._generateGLTFAsync(glTFPrefix);
             });
         }
 
+        private static _PreExportAsync(scene: Scene, options?: IExportOptions): Promise<void> {
+            return Promise.resolve().then(() => {
+                if (options && options.exportWithoutWaitingForScene) {
+                    return Promise.resolve();
+                }
+                else {
+                    return scene.whenReadyAsync();
+                }
+            });
+        }
+
+        private static _PostExportAsync(scene: Scene, glTFData: GLTFData, options?: IExportOptions): Promise<GLTFData> {
+            return Promise.resolve().then(() => {
+                if (options && options.exportWithoutWaitingForScene) {
+                    return glTFData;
+                }
+                else {
+                    return glTFData;
+                }
+            });
+        }
+
         /**
          * Exports the geometry of the scene to .glb file format asychronously
          * @param scene Babylon scene with scene hierarchy information
@@ -45,10 +72,12 @@ module BABYLON {
          * @returns Returns an object with a .glb filename as key and data as value
          */
         public static GLBAsync(scene: Scene, filePrefix: string, options?: IExportOptions): Promise<GLTFData> {
-            return scene.whenReadyAsync().then(() => {
+            return this._PreExportAsync(scene, options).then(() => {
                 const glTFPrefix = filePrefix.replace(/\.[^/.]+$/, "");
-                const gltfGenerator = new GLTF2._Exporter(scene, options);
-                return gltfGenerator._generateGLBAsync(glTFPrefix);
+                const gltfGenerator = new GLTF2.Exporter._Exporter(scene, options);
+                return gltfGenerator._generateGLBAsync(glTFPrefix).then(glTFData => {
+                    return this._PostExportAsync(scene, glTFData, options);
+                });
             });
         }
     }

+ 1 - 1
serializers/src/glTF/2.0/babylon.glTFUtilities.ts

@@ -1,6 +1,6 @@
 /// <reference path="../../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
 
-module BABYLON.GLTF2 {
+module BABYLON.GLTF2.Exporter {
     /**
      * @hidden
      */

+ 11 - 0
serializers/src/glTF/2.0/shaders/textureTransform.fragment.fx

@@ -0,0 +1,11 @@
+precision highp float;
+
+varying vec2 vUV;
+
+uniform sampler2D textureSampler;
+uniform mat4 textureTransformMat;
+
+void main(void) {
+	vec2 uvTransformed = (textureTransformMat * vec4(vUV.xy, 1, 1)).xy;
+	gl_FragColor = texture2D(textureSampler, uvTransformed);
+}

+ 23 - 0
serializers/src/glTF/babylon.glTFFileExporter.ts

@@ -0,0 +1,23 @@
+/// <reference path="../../../dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts"/>
+
+module BABYLON {
+    /**
+     * Interface for extending the exporter
+     * @hidden
+     */
+    export interface IGLTFExporterExtension {
+        /**
+         * The name of this extension
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled
+         */
+        enabled: boolean;
+
+        /**
+         * Defines whether this extension is required
+         */
+        required: boolean;
+    }
+}

+ 3 - 2
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -16,7 +16,8 @@
 
         private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
         private _indexBuffer: Nullable<WebGLBuffer>;
-        private _effect: Effect;
+        /** get the internal effect */
+        public _effect: Effect;
 
         private _uniforms = new Array<string>();
         private _samplers = new Array<string>();
@@ -170,7 +171,7 @@
 
                     this._fallbackTextureUsed = true;
                 });
-
+                
             return this._effect.isReady();
         }
 

+ 3 - 3
tests/unit/babylon/serializers/babylon.glTFSerializer.tests.ts

@@ -42,7 +42,7 @@ describe('Babylon glTF Serializer', () => {
             babylonStandardMaterial.specularColor = BABYLON.Color3.Black();
             babylonStandardMaterial.specularPower = 64;
             babylonStandardMaterial.alpha = 1;
-            const materialExporter = new BABYLON.GLTF2._GLTFMaterialExporter(new BABYLON.GLTF2._Exporter(scene));
+            const materialExporter = new BABYLON.GLTF2.Exporter._GLTFMaterialExporter(new BABYLON.GLTF2.Exporter._Exporter(scene));
 
             const metalRough = materialExporter._convertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
 
@@ -53,8 +53,8 @@ describe('Babylon glTF Serializer', () => {
             metalRough.roughnessFactor.should.be.approximately(0.328809, 1e-6);
         });
         it('should solve for metallic', () => {
-            BABYLON.GLTF2._GLTFMaterialExporter._SolveMetallic(1.0, 0.0, 1.0).should.be.equal(0);
-            BABYLON.GLTF2._GLTFMaterialExporter._SolveMetallic(0.0, 1.0, 1.0).should.be.approximately(1, 1e-6);
+            BABYLON.GLTF2.Exporter._GLTFMaterialExporter._SolveMetallic(1.0, 0.0, 1.0).should.be.equal(0);
+            BABYLON.GLTF2.Exporter._GLTFMaterialExporter._SolveMetallic(0.0, 1.0, 1.0).should.be.approximately(1, 1e-6);
         });
         it('should serialize empty Babylon scene to glTF with only asset property', () => {
             const scene = new BABYLON.Scene(subject);

TEMPAT SAMPAH
tests/validation/ReferenceImages/glTFSerializerTextureTransform.png


+ 5 - 0
tests/validation/config.json

@@ -313,6 +313,11 @@
       "referenceImage": "gltfMaterialSpecularGlossiness.png"
     },
     {
+      "title": "GLTF Serializer Texture Transform",
+      "playgroundId": "#S5SWJB#32",
+      "referenceImage": "glTFSerializerTextureTransform.png"
+    }, 
+    {
       "title": "GLTF Texture Sampler",
       "scriptToRun": "/Demos/GLTFTests/index.js",
       "functionToCall": "createTextureSamplerScene",

+ 14 - 1
tests/validation/validation.js

@@ -264,7 +264,20 @@ function runTest(index, done) {
                         code = code.replace(/\/scenes\//g, pgRoot + "/scenes/");
                         code = code.replace(/"scenes\//g, "\"" + pgRoot + "/scenes/");
                         currentScene = eval(code + "\r\ncreateScene(engine)");
-                        processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+
+                        if(currentScene.then){
+                            // Handle if createScene returns a promise
+                            currentScene.then(function(scene){
+                                currentScene = scene;
+                                processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+                            }).catch(function(e){
+                                console.error(e);
+                                onError();
+                            })
+                        }else{
+                            // Handle if createScene returns a scene
+                            processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+                        }
                     }
                     catch (e) {
                         console.error(e);