瀏覽代碼

Merge remote-tracking branch 'upstream/master'

sebastien 7 年之前
父節點
當前提交
a6e56d5101
共有 83 個文件被更改,包括 21699 次插入20501 次删除
  1. 4 2
      .travis.yml
  2. 10082 9986
      Playground/babylon.d.txt
  3. 15 2
      Tools/Gulp/config.json
  4. 35 0
      Tools/Gulp/gulpfile.js
  5. 二進制
      Viewer/tests/validation/ReferenceImages/Control.png
  6. 二進制
      Viewer/tests/validation/ReferenceImages/ControlDefault.png
  7. 二進制
      Viewer/tests/validation/ReferenceImages/Diffuse.png
  8. 二進制
      Viewer/tests/validation/ReferenceImages/Emissive.png
  9. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv0-0.png
  10. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv0-100.png
  11. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv0-50.png
  12. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv100-0.png
  13. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv100-100.png
  14. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv100-50.png
  15. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv50-0.png
  16. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv50-100.png
  17. 二進制
      Viewer/tests/validation/ReferenceImages/MainColorEnv50-50.png
  18. 二進制
      Viewer/tests/validation/ReferenceImages/Specular0-0.png
  19. 二進制
      Viewer/tests/validation/ReferenceImages/Specular0-100.png
  20. 二進制
      Viewer/tests/validation/ReferenceImages/Specular0-25.png
  21. 二進制
      Viewer/tests/validation/ReferenceImages/Specular0-50.png
  22. 二進制
      Viewer/tests/validation/ReferenceImages/Specular0-75.png
  23. 二進制
      Viewer/tests/validation/ReferenceImages/Specular100-0.png
  24. 二進制
      Viewer/tests/validation/ReferenceImages/Specular100-100.png
  25. 二進制
      Viewer/tests/validation/ReferenceImages/Specular100-25.png
  26. 二進制
      Viewer/tests/validation/ReferenceImages/Specular100-50.png
  27. 二進制
      Viewer/tests/validation/ReferenceImages/Specular100-75.png
  28. 二進制
      Viewer/tests/validation/ReferenceImages/Specular25-0.png
  29. 二進制
      Viewer/tests/validation/ReferenceImages/Specular25-100.png
  30. 二進制
      Viewer/tests/validation/ReferenceImages/Specular25-25.png
  31. 二進制
      Viewer/tests/validation/ReferenceImages/Specular25-50.png
  32. 二進制
      Viewer/tests/validation/ReferenceImages/Specular25-75.png
  33. 二進制
      Viewer/tests/validation/ReferenceImages/Specular50-0.png
  34. 二進制
      Viewer/tests/validation/ReferenceImages/Specular50-100.png
  35. 二進制
      Viewer/tests/validation/ReferenceImages/Specular50-25.png
  36. 二進制
      Viewer/tests/validation/ReferenceImages/Specular50-50.png
  37. 二進制
      Viewer/tests/validation/ReferenceImages/Specular50-75.png
  38. 二進制
      Viewer/tests/validation/ReferenceImages/Specular75-0.png
  39. 二進制
      Viewer/tests/validation/ReferenceImages/Specular75-100.png
  40. 二進制
      Viewer/tests/validation/ReferenceImages/Specular75-25.png
  41. 二進制
      Viewer/tests/validation/ReferenceImages/Specular75-50.png
  42. 二進制
      Viewer/tests/validation/ReferenceImages/Specular75-75.png
  43. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv0-0.png
  44. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv0-100.png
  45. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv0-50.png
  46. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv100-0.png
  47. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv100-100.png
  48. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv100-50.png
  49. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv50-0.png
  50. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv50-100.png
  51. 二進制
      Viewer/tests/validation/ReferenceImages/SpecularEnv50-50.png
  52. 44 8
      Viewer/tests/validation/config.json
  53. 1 1
      Viewer/tests/validation/integration.js
  54. 14 20
      Viewer/tests/validation/karma.conf.browserstack.js
  55. 39 40
      Viewer/tests/validation/validation.js
  56. 10077 9981
      dist/preview release/babylon.d.ts
  57. 46 46
      dist/preview release/babylon.js
  58. 241 76
      dist/preview release/babylon.max.js
  59. 241 76
      dist/preview release/babylon.no-module.max.js
  60. 30 30
      dist/preview release/babylon.worker.js
  61. 243 78
      dist/preview release/es6.js
  62. 6 4
      dist/preview release/serializers/babylon.glTF2Serializer.js
  63. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  64. 6 4
      dist/preview release/serializers/babylonjs.serializers.js
  65. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  66. 2 11
      dist/preview release/typedocValidationBaseline.json
  67. 40 40
      dist/preview release/viewer/babylon.viewer.js
  68. 241 76
      dist/preview release/viewer/babylon.viewer.max.js
  69. 2 2
      dist/preview release/what's new.md
  70. 24 0
      src/Behaviors/Mesh/babylon.pointerDragBehavior.ts
  71. 20 1
      src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts
  72. 14 6
      src/Gizmos/babylon.boundingBoxGizmo.ts
  73. 1 6
      src/Gizmos/babylon.gizmoManager.ts
  74. 6 0
      src/Helpers/babylon.photoDome.ts
  75. 6 0
      src/Helpers/babylon.videoDome.ts
  76. 86 0
      src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.ts
  77. 22 1
      src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts
  78. 18 1
      src/Rendering/babylon.utilityLayerRenderer.ts
  79. 78 0
      src/Shaders/noise.fragment.fx
  80. 1 1
      src/babylon.scene.ts
  81. 二進制
      tests/validation/ReferenceImages/Gizmos.png
  82. 二進制
      tests/validation/ReferenceImages/spherepanel.png
  83. 12 0
      tests/validation/config.json

文件差異過大導致無法顯示
+ 4 - 2
.travis.yml


文件差異過大導致無法顯示
+ 10082 - 9986
Playground/babylon.d.txt


+ 15 - 2
Tools/Gulp/config.json

@@ -122,7 +122,8 @@
             "behaviors",
             "imageProcessing",
             "occlusionQuery",
-            "transformFeedback"     
+            "transformFeedback",
+            "noise"
         ],
         "minimal": [
             "meshBuilder",
@@ -272,7 +273,19 @@
             "dependUpon": [
                 "core"
             ]
-        },        
+        },  
+        "noise" : {
+            "files": [
+                "../../src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.js"
+            ],
+            "dependUpon": [
+                "core",
+                "procedural"
+            ],
+            "shaders": [
+                "noise.fragment"
+            ]
+        },      
         "particles": {
             "files": [
                 "../../src/Particles/babylon.particle.js",

+ 35 - 0
Tools/Gulp/gulpfile.js

@@ -1092,6 +1092,41 @@ gulp.task("tests-viewer-validation-karma", ["tests-viewer-validation-transpile"]
 });
 
 /**
+ * Launches the KARMA validation tests in ff or virtual screen ff on travis for a quick analysis during the build.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-viewer-validation-virtualscreen", ["tests-viewer-validation-transpile"], function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../Viewer/tests/validation/karma.conf.js",
+        singleRun: true,
+        browsers: ['Firefox']
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Launches the KARMA validation tests in browser stack for remote and cross devices validation tests.
+ * (Can only be launch from secure branches.)
+ */
+gulp.task("tests-viewer-validation-browserstack", ["tests-viewer-validation-transpile"], function (done) {
+    if (!process.env.BROWSER_STACK_USERNAME) {
+        done();
+        return;
+    }
+
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../Viewer/tests/validation/karma.conf.browserstack.js",
+        singleRun: true
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+
+/**
  * Transpiles viewer typescript unit tests. 
  */
 gulp.task("tests-viewer-validation-transpile", function (done) {

二進制
Viewer/tests/validation/ReferenceImages/Control.png


二進制
Viewer/tests/validation/ReferenceImages/ControlDefault.png


二進制
Viewer/tests/validation/ReferenceImages/Diffuse.png


二進制
Viewer/tests/validation/ReferenceImages/Emissive.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv0-0.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv0-100.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv0-50.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv100-0.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv100-100.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv100-50.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv50-0.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv50-100.png


二進制
Viewer/tests/validation/ReferenceImages/MainColorEnv50-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular0-0.png


二進制
Viewer/tests/validation/ReferenceImages/Specular0-100.png


二進制
Viewer/tests/validation/ReferenceImages/Specular0-25.png


二進制
Viewer/tests/validation/ReferenceImages/Specular0-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular0-75.png


二進制
Viewer/tests/validation/ReferenceImages/Specular100-0.png


二進制
Viewer/tests/validation/ReferenceImages/Specular100-100.png


二進制
Viewer/tests/validation/ReferenceImages/Specular100-25.png


二進制
Viewer/tests/validation/ReferenceImages/Specular100-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular100-75.png


二進制
Viewer/tests/validation/ReferenceImages/Specular25-0.png


二進制
Viewer/tests/validation/ReferenceImages/Specular25-100.png


二進制
Viewer/tests/validation/ReferenceImages/Specular25-25.png


二進制
Viewer/tests/validation/ReferenceImages/Specular25-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular25-75.png


二進制
Viewer/tests/validation/ReferenceImages/Specular50-0.png


二進制
Viewer/tests/validation/ReferenceImages/Specular50-100.png


二進制
Viewer/tests/validation/ReferenceImages/Specular50-25.png


二進制
Viewer/tests/validation/ReferenceImages/Specular50-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular50-75.png


二進制
Viewer/tests/validation/ReferenceImages/Specular75-0.png


二進制
Viewer/tests/validation/ReferenceImages/Specular75-100.png


二進制
Viewer/tests/validation/ReferenceImages/Specular75-25.png


二進制
Viewer/tests/validation/ReferenceImages/Specular75-50.png


二進制
Viewer/tests/validation/ReferenceImages/Specular75-75.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv0-0.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv0-100.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv0-50.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv100-0.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv100-100.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv100-50.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv50-0.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv50-100.png


二進制
Viewer/tests/validation/ReferenceImages/SpecularEnv50-50.png


+ 44 - 8
Viewer/tests/validation/config.json

@@ -2,10 +2,46 @@
     "root": "",
     "tests": [
         {
+            "title": "Diffuse",
+            "createMesh": true,
+            "createMaterial": true,
+            "configuration": {
+                "extends": "extended",
+                "castShadow": true,
+                "model": {
+                    "material": {
+                        "albedoColor": {
+                            "r": 0,
+                            "g": 0,
+                            "b": 1
+                        },
+                        "reflectivityColor": {
+                            "r": 0,
+                            "g": 0,
+                            "b": 0
+                        },
+                        "microSurface": 0
+                    }
+                }
+            },
+            "referenceImage": "Diffuse.png"
+        },
+        {
+            "title": "BrainStem Environment",
+            "configuration": {
+                "extends": "extended"
+            },
+            "model": "/dist/assets/BrainStem/BrainStem.gltf",
+            "referenceImage": "BrainStemEnv.png",
+            "enableEnvironment": true
+        }
+    ],
+    "allTests": [
+        {
             "title": "Control Default",
             "createMesh": true,
             "configuration": {
-                "extends": "default"
+                "extends": "minimal"
             },
             "referenceImage": "ControlDefault.png"
         },
@@ -254,11 +290,11 @@
             "enableEnvironment": true
         },
         {
-            "title": "Specular {{glos * 25}} - {{spec * 25}}",
+            "title": "Specular {{glos * 50}} - {{spec * 50}}",
             "createMesh": true,
             "createMaterial": true,
             "repeatVariables": "glos,spec",
-            "repeatTimes": "5,5",
+            "repeatTimes": "3,3",
             "configuration": {
                 "extends": "extended",
                 "castShadow": true,
@@ -270,15 +306,15 @@
                             "b": 1
                         },
                         "reflectivityColor": {
-                            "r": "{{spec / 4}}",
-                            "g": "{{spec / 4}}",
-                            "b": "{{spec / 4}}"
+                            "r": "{{spec / 2}}",
+                            "g": "{{spec / 2}}",
+                            "b": "{{spec / 2}}"
                         },
-                        "microSurface": "{{glos / 4}}"
+                        "microSurface": "{{glos / 2}}"
                     }
                 }
             },
-            "referenceImage": "Specular{{glos * 25}}-{{spec * 25}}.png"
+            "referenceImage": "Specular{{glos * 50}}-{{spec * 50}}.png"
         },
         {
             "title": "BrainStem",

+ 1 - 1
Viewer/tests/validation/integration.js

@@ -67,7 +67,7 @@ window.onload = function () {
                                 }
                                 catch (e) {
                                     if (screenshot) {
-                                        console.error(screenshot);
+                                        //console.error(screenshot);
                                     }
                                     deferredDone(e);
                                 }

+ 14 - 20
Viewer/tests/validation/karma.conf.browserstack.js

@@ -9,27 +9,21 @@ module.exports = function (config) {
         browserDisconnectTolerance: 3,
         concurrency: 1,
 
-        urlRoot: '/karma',
+        urlRoot: '/karma/',
 
         frameworks: ['mocha', 'chai', 'sinon'],
 
         files: [
-            './dist/preview release/earcut.min.js',
-            './Tools/DevLoader/BabylonLoader.js',
             './tests/validation/index.css',
             './tests/validation/integration.js',
-            './favicon.ico',
-            { pattern: 'dist/**/*', watched: false, included: false, served: true },
-            { pattern: 'assets/**/*', watched: false, included: false, served: true },
-            { pattern: 'tests/**/*', watched: false, included: false, served: true },
-            { pattern: 'Playground/scenes/**/*', watched: false, included: false, served: true },
-            { pattern: 'Playground/textures/**/*', watched: false, included: false, served: true },
-            { pattern: 'Playground/sounds/**/*', watched: false, included: false, served: true },
-            { pattern: 'Tools/DevLoader/**/*', watched: false, included: false, served: true },            
-            { pattern: 'Tools/Gulp/config.json', watched: false, included: false, served: true },
+            './tests/build/test.js',
+            './tests/validation/validation.js',
+            { pattern: './tests/**/*', watched: false, included: false, served: true },
+            { pattern: './dist/assets/**/*', watched: false, included: false, served: true },
         ],
         proxies: {
-            '/': '/base/'
+            '/tests/': '/base/tests/',
+            '/dist/assets/': '/base//dist/assets/'
         },
 
         port: 1338,
@@ -44,7 +38,7 @@ module.exports = function (config) {
         browserStack: {
             project: 'Babylon JS Validation Tests',
             video: false,
-            debug : 'true',
+            debug: 'true',
             timeout: 1200,
             build: process.env.TRAVIS_BUILD_NUMBER,
             username: process.env.BROWSER_STACK_USERNAME,
@@ -75,16 +69,16 @@ module.exports = function (config) {
             bs_chrome_android: {
                 base: 'BrowserStack',
                 os: 'Android',
-                os_version : '8.0',
-                device : 'Google Pixel',
-                real_mobile : 'true'
+                os_version: '8.0',
+                device: 'Google Pixel',
+                real_mobile: 'true'
             },
             bs_safari_ios: {
                 base: 'BrowserStack',
                 os: 'ios',
-                os_version : '10.3',
-                device : 'iPhone 7',
-                real_mobile : 'true'
+                os_version: '10.3',
+                device: 'iPhone 7',
+                real_mobile: 'true'
             }
         },
         browsers: ['bs_chrome_android'],

+ 39 - 40
Viewer/tests/validation/validation.js

@@ -138,6 +138,8 @@ function evaluate(test, resultCanvas, result, renderImage, index, waitRing, done
 
     var renderB64 = saveRenderImage(renderData, currentViewer.canvas);
     renderImage.src = renderB64;
+
+    // save all reference images
     // downloadDataUrlFromJavascript(test.referenceImage, renderB64)
 
     done(testRes, renderB64);
@@ -151,11 +153,6 @@ function runTest(index, done) {
 
     var test = Object.assign({}, config.tests[index]);
 
-    //process params
-    /*if (params) {
-        processTest(test, "", params);
-    }*/
-
     var container = document.createElement("div");
     container.id = "container#" + index;
     container.className = "container";
@@ -236,35 +233,42 @@ function runTest(index, done) {
 
     // create a new viewer
     currentViewer && currentViewer.dispose();
-    currentViewer = null;
-    currentScene = null;
-    viewerElement.innerHTML = '';
-    currentViewer = new BabylonViewer.DefaultViewer(viewerElement, configuration);
-
-    currentViewer.onInitDoneObservable.add(() => {
-
-        var currentFrame = 0;
-        var waitForFrame = test.waitForFrame || 0;
-
-        if (test.model) {
-            currentViewer.initModel(test.model);
-        } else if (test.createMesh) {
-            prepareMeshForViewer(currentViewer, configuration, test);
-        }
-
-        currentViewer.onModelLoadedObservable.add((model) => {
-            currentViewer.onFrameRenderedObservable.add(() => {
-                if (test.animationTest && !currentFrame) {
-                    model.playAnimation(model.getAnimationNames()[0]);
-                }
-                if (currentFrame === waitForFrame) {
-                    currentViewer.sceneManager.scene.executeWhenReady(() => {
-                        evaluate(test, resultCanvas, result, renderImage, index, waitRing, done);
-                    });
-                }
-                currentFrame++;
+    currentViewer && currentViewer.engine.dispose();
+
+    setTimeout(() => {
+        currentViewer = null;
+        currentScene = null;
+        viewerElement.innerHTML = '';
+        currentViewer = new BabylonViewer.DefaultViewer(viewerElement, configuration);
+
+        currentViewer.onInitDoneObservable.add(() => {
+
+            var currentFrame = 0;
+            var waitForFrame = test.waitForFrame || 0;
+
+            currentViewer.onModelLoadedObservable.add((model) => {
+                console.log("model loaded");
+                currentViewer.onFrameRenderedObservable.add(() => {
+                    console.log("frame rendered", currentFrame, model.meshes.every(m => m.isReady()));
+                    if (test.animationTest && !currentFrame) {
+                        model.playAnimation(model.getAnimationNames()[0]);
+                    }
+                    if (currentFrame === waitForFrame) {
+                        currentViewer.onFrameRenderedObservable.clear();
+                        currentViewer.sceneManager.scene.executeWhenReady(() => {
+                            evaluate(test, resultCanvas, result, renderImage, index, waitRing, done);
+                        });
+                    }
+                    currentFrame++;
+                });
             });
-        })
+
+            if (test.model) {
+                currentViewer.initModel(test.model);
+            } else if (test.createMesh) {
+                prepareMeshForViewer(currentViewer, configuration, test);
+            }
+        });
     });
 }
 
@@ -274,16 +278,11 @@ function prepareMeshForViewer(viewer, configuration, test) {
     let sphereMesh = BABYLON.Mesh.CreateSphere('sphere-' + test.title, 20, 1.0, viewer.sceneManager.scene);
     if (test.createMaterial) {
         let material = new BABYLON.PBRMaterial("sphereMat", viewer.sceneManager.scene);
-        /* material.useAlphaFresnel = material.needAlphaBlending();
-         material.backFaceCulling = material.forceDepthWrite;
-         material.twoSidedLighting = true;
-         material.useSpecularOverAlpha = false;
-         material.useRadianceOverAlpha = false;
-         material.usePhysicalLightFalloff = true;
-         material.forceNormalForward = true;*/
         sphereMesh.material = material;
     }
     meshModel.addMesh(sphereMesh, true);
+    meshModel.rootMesh.position.y = 0.5;
+    console.log("sphere created");
 }
 
 function init() {

文件差異過大導致無法顯示
+ 10077 - 9981
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 46 - 46
dist/preview release/babylon.js


文件差異過大導致無法顯示
+ 241 - 76
dist/preview release/babylon.max.js


文件差異過大導致無法顯示
+ 241 - 76
dist/preview release/babylon.no-module.max.js


文件差異過大導致無法顯示
+ 30 - 30
dist/preview release/babylon.worker.js


文件差異過大導致無法顯示
+ 243 - 78
dist/preview release/es6.js


+ 6 - 4
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -3276,10 +3276,12 @@ var BABYLON;
                 quaternion[1] *= -1;
             };
             _GLTFUtilities._NormalizeTangentFromRef = function (tangent) {
-                var length = Math.sqrt(tangent.x * tangent.x + tangent.y * tangent.y + tangent.z + tangent.z);
-                tangent.x /= length;
-                tangent.y /= length;
-                tangent.z /= length;
+                var length = Math.sqrt(tangent.x * tangent.x + tangent.y * tangent.y + tangent.z * tangent.z);
+                if (length > 0) {
+                    tangent.x /= length;
+                    tangent.y /= length;
+                    tangent.z /= length;
+                }
             };
             return _GLTFUtilities;
         }());

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 6 - 4
dist/preview release/serializers/babylonjs.serializers.js

@@ -3437,10 +3437,12 @@ var BABYLON;
                 quaternion[1] *= -1;
             };
             _GLTFUtilities._NormalizeTangentFromRef = function (tangent) {
-                var length = Math.sqrt(tangent.x * tangent.x + tangent.y * tangent.y + tangent.z + tangent.z);
-                tangent.x /= length;
-                tangent.y /= length;
-                tangent.z /= length;
+                var length = Math.sqrt(tangent.x * tangent.x + tangent.y * tangent.y + tangent.z * tangent.z);
+                if (length > 0) {
+                    tangent.x /= length;
+                    tangent.y /= length;
+                    tangent.z /= length;
+                }
             };
             return _GLTFUtilities;
         }());

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 2 - 11
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 4240,
+  "errors": 4239,
   "babylon.typedoc.json": {
-    "errors": 4240,
+    "errors": 4239,
     "AbstractMesh": {
       "Property": {
         "showBoundingBox": {
@@ -20639,15 +20639,6 @@
         }
       }
     },
-    "UtilityLayerRenderer": {
-      "Property": {
-        "DefaultUtilityLayer": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "VRCameraMetrics": {
       "Class": {
         "Comments": {

文件差異過大導致無法顯示
+ 40 - 40
dist/preview release/viewer/babylon.viewer.js


文件差異過大導致無法顯示
+ 241 - 76
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -7,7 +7,7 @@
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 - 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))
 - New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-- 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))
+- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, rotation, scale 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))
 - 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))
@@ -148,7 +148,7 @@
 - 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 to use existing ones ([RaananW](https://github.com/RaananW))
+- It was not possible to add new custom optimizers, only use existing ones ([RaananW](https://github.com/RaananW))
 
 ### Loaders
 

+ 24 - 0
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -65,6 +65,10 @@ module BABYLON {
          *  If the drag behavior will react to drag events (Default: true)
          */
         public enabled = true;
+        /**
+         * If camera controls should be detached during the drag
+         */
+        public detachCameraControls = true;
         
         /**
          * If set, the drag plane/axis will be rotated based on the attached mesh's world rotation (Default: true)
@@ -122,6 +126,10 @@ module BABYLON {
                     PointerDragBehavior._planeScene = new BABYLON.Scene(this._scene.getEngine());
                     PointerDragBehavior._planeScene.detachControl();
                     this._scene.getEngine().scenes.pop();
+                    this._scene.onDisposeObservable.addOnce(()=>{
+                        PointerDragBehavior._planeScene.dispose();
+                        (<any>PointerDragBehavior._planeScene) = null;
+                    })
                 }
             }
             this._dragPlane = BABYLON.Mesh.CreatePlane("pointerDragPlane", this._debugMode ? 1 : 10000, PointerDragBehavior._planeScene, false, BABYLON.Mesh.DOUBLESIDE);
@@ -136,6 +144,7 @@ module BABYLON {
                 return this._attachedNode == m || m.isDescendantOf(this._attachedNode)
             }
 
+            var attachedElement:Nullable<HTMLElement> = null;
             this._pointerObserver = this._scene.onPointerObservable.add((pointerInfo, eventState)=>{
                 if(!this.enabled){
                     return;
@@ -152,11 +161,26 @@ module BABYLON {
                             this.lastDragPosition.copyFrom(pickedPoint);
                             this.onDragStartObservable.notifyObservers({dragPlanePoint: pickedPoint, pointerId: this.currentDraggingPointerID});
                             targetPosition.copyFrom((<Mesh>this._attachedNode).absolutePosition)
+
+                            // Detatch camera controls
+                            if(this.detachCameraControls && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
+                                if(this._scene.activeCamera.inputs.attachedElement){
+                                    attachedElement = this._scene.activeCamera.inputs.attachedElement;
+                                    this._scene.activeCamera.detachControl(this._scene.activeCamera.inputs.attachedElement);
+                                }else{
+                                    attachedElement = null;
+                                }
+                            }
                         }
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId){
                         this.releaseDrag();
+
+                        // Reattach camera controls
+                        if(this.detachCameraControls && attachedElement && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
+                            this._scene.activeCamera.attachControl(attachedElement, true);
+                        }
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId && this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray){

+ 20 - 1
src/Behaviors/Mesh/babylon.sixDofDragBehavior.ts

@@ -29,6 +29,10 @@ module BABYLON {
          * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
          */
         public currentDraggingPointerID = -1;
+        /**
+         * If camera controls should be detached during the drag
+         */
+        public detachCameraControls = true;
 
 
         constructor(){
@@ -70,7 +74,7 @@ module BABYLON {
             var pickPredicate = (m:AbstractMesh)=>{
                 return this._ownerNode == m || m.isDescendantOf(this._ownerNode);
             }
-            
+            var attachedElement:Nullable<HTMLElement> = null;
             this._pointerObserver = this._scene.onPointerObservable.add((pointerInfo, eventState)=>{                
                 if (pointerInfo.type == BABYLON.PointerEventTypes.POINTERDOWN) {
                     if(!this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh && pointerInfo.pickInfo.ray && pickPredicate(pointerInfo.pickInfo.pickedMesh)){
@@ -101,6 +105,16 @@ module BABYLON {
                         this._targetPosition.copyFrom(this._virtualDragMesh.absolutePosition);
                         this.dragging = true;
                         this.currentDraggingPointerID = (<PointerEvent>pointerInfo.event).pointerId;
+
+                        // Detatch camera controls
+                        if(this.detachCameraControls && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
+                            if(this._scene.activeCamera.inputs.attachedElement){
+                                attachedElement = this._scene.activeCamera.inputs.attachedElement;
+                                this._scene.activeCamera.detachControl(this._scene.activeCamera.inputs.attachedElement);
+                            }else{
+                                attachedElement = null;
+                            }
+                        }
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERUP){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId){
@@ -109,6 +123,11 @@ module BABYLON {
                         this.currentDraggingPointerID = -1;
                         pickedMesh = null;
                         this._virtualOriginMesh.removeChild(this._virtualDragMesh);
+                        
+                        // Reattach camera controls
+                        if(this.detachCameraControls && attachedElement && this._scene.activeCamera && !this._scene.activeCamera.leftCamera){
+                            this._scene.activeCamera.attachControl(attachedElement, true);
+                        }
                     }
                 }else if(pointerInfo.type == BABYLON.PointerEventTypes.POINTERMOVE){
                     if(this.currentDraggingPointerID == (<PointerEvent>pointerInfo.event).pointerId && this.dragging && pointerInfo.pickInfo && pointerInfo.pickInfo.ray && pickedMesh){

+ 14 - 6
src/Gizmos/babylon.boundingBoxGizmo.ts

@@ -44,12 +44,13 @@ module BABYLON {
          */
         public onDragEndObservable = new Observable<{}>();
         private _anchorMesh:AbstractMesh;
+        private _existingMeshScale = new Vector3();
         /**
          * Creates an BoundingBoxGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
          * @param color The color of the gizmo
          */
-        constructor(color:Color3 = Color3.Gray(), gizmoLayer:UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer){
+        constructor(color:Color3 = Color3.Gray(), gizmoLayer:UtilityLayerRenderer = UtilityLayerRenderer.DefaultKeepDepthUtilityLayer){
             super(gizmoLayer);
 
             // Do not update the gizmo's scale so it has a fixed size to the object its attached to
@@ -143,6 +144,7 @@ module BABYLON {
                             this._anchorMesh.rotationQuaternion!.multiplyToRef(this._tmpQuaternion,this._anchorMesh.rotationQuaternion!);
                             this._anchorMesh.removeChild(this.attachedMesh);
                         }
+                        this.updateBoundingBox(); 
                     }
                 });
 
@@ -179,7 +181,7 @@ module BABYLON {
                             if(this.attachedMesh){
                                 var deltaScale = new Vector3(event.dragDistance,event.dragDistance,event.dragDistance);
                                 deltaScale.scaleInPlace(this._scaleDragSpeed);
-                                this._updateBoundingBox(); 
+                                this.updateBoundingBox(); 
 
                                  // Scale from the position of the opposite corner                   
                                 box.absolutePosition.subtractToRef(this._anchorMesh.position, this._tmpVector);
@@ -229,9 +231,12 @@ module BABYLON {
 
             // Update bounding box positions
             this._renderObserver = this.gizmoLayer.originalScene.onBeforeRenderObservable.add(()=>{
-                this._updateBoundingBox();
+                // Only update the bouding box if scaling has changed
+                if(this.attachedMesh && !this._existingMeshScale.equals(this.attachedMesh.scaling)){
+                    this.updateBoundingBox();
+                }
             })
-            this._updateBoundingBox();
+            this.updateBoundingBox();
         }
         
         protected _attachedMeshChanged(value:Nullable<AbstractMesh>){
@@ -240,7 +245,7 @@ module BABYLON {
                 // This is needed to avoid invalid box/sphere position on first drag
                 this._anchorMesh.addChild(value);
                 this._anchorMesh.removeChild(value);
-                this._updateBoundingBox();
+                this.updateBoundingBox();
             }
         }
 
@@ -258,7 +263,7 @@ module BABYLON {
             });
         }
 
-        private _updateBoundingBox(){
+        public updateBoundingBox(){
             if(this.attachedMesh){             
                 // Rotate based on axis
                 if(!this.attachedMesh.rotationQuaternion){
@@ -345,6 +350,9 @@ module BABYLON {
                     }
                 }
             }
+            if(this.attachedMesh){
+                this._existingMeshScale.copyFrom(this.attachedMesh.scaling);
+            }
         }
 
         /**

+ 1 - 6
src/Gizmos/babylon.gizmoManager.ts

@@ -12,7 +12,6 @@ module BABYLON {
         private _pointerObserver:Nullable<Observer<PointerInfo>> = null;
         private _attachedMesh:Nullable<AbstractMesh> = null;
         private _boundingBoxColor = BABYLON.Color3.FromHexString("#0984e3");
-        private _boundingBoxUtilLayer:Nullable<UtilityLayerRenderer> = null;
         private _dragBehavior = new BABYLON.SixDofDragBehavior();
         /**
          * Array of meshes which will have the gizmo attached when a pointer selected them. If null, all meshes are attachable. (Default: null)
@@ -138,11 +137,7 @@ module BABYLON {
          */
         public set boundingBoxGizmoEnabled(value:boolean){
             if(value){
-                if(!this._boundingBoxUtilLayer){
-                    this._boundingBoxUtilLayer = new BABYLON.UtilityLayerRenderer(this.scene);
-                    this._boundingBoxUtilLayer.utilityLayerScene.autoClearDepthAndStencil = false;
-                }
-                this.gizmos.boundingBoxGizmo = this.gizmos.boundingBoxGizmo || new BoundingBoxGizmo(this._boundingBoxColor, this._boundingBoxUtilLayer);
+                this.gizmos.boundingBoxGizmo = this.gizmos.boundingBoxGizmo || new BoundingBoxGizmo(this._boundingBoxColor);
                 this.gizmos.boundingBoxGizmo.attachedMesh = this._attachedMesh;
                 if(this._attachedMesh){
                     this._attachedMesh.removeBehavior(this._dragBehavior);

+ 6 - 0
src/Helpers/babylon.photoDome.ts

@@ -82,6 +82,8 @@ module BABYLON {
                 this._useDirectMapping = options.useDirectMapping;            
             }
 
+            this._setReady(false);
+
             // create
             let material = this._material = new BackgroundMaterial(name + "_material", scene);
             this._mesh = BABYLON.Mesh.CreateSphere(name + "_mesh", options.resolution, options.size, scene, false, BABYLON.Mesh.BACKSIDE);
@@ -92,6 +94,10 @@ module BABYLON {
             material.fovMultiplier = 1.0;
 
             this.photoTexture = new Texture(urlOfPhoto, scene, true, !this._useDirectMapping);
+
+            this.photoTexture.onLoadObservable.addOnce(()=> {
+                this._setReady(true);
+            }) ;             
            
             // configure mesh
             this._mesh.material = material;

+ 6 - 0
src/Helpers/babylon.videoDome.ts

@@ -72,12 +72,18 @@ module BABYLON {
                 this._useDirectMapping = options.useDirectMapping;            
             }
 
+            this._setReady(false);
+
             // create
             let tempOptions: VideoTextureSettings = { loop: options.loop, autoPlay: options.autoPlay, autoUpdateTexture: true, poster: options.poster };
             let material = this._material = new BackgroundMaterial(name + "_material", scene);
             let texture = this._videoTexture = new VideoTexture(name + "_texture", urlsOrVideo, scene, false, this._useDirectMapping, Texture.TRILINEAR_SAMPLINGMODE, tempOptions);
             this._mesh = BABYLON.Mesh.CreateSphere(name + "_mesh", options.resolution, options.size, scene, false, BABYLON.Mesh.BACKSIDE);
 
+            texture.onLoadObservable.addOnce(()=> {
+                this._setReady(true);
+            }) ;          
+
             // configure material
             material.useEquirectangularFOV = true;
             material.fovMultiplier = 1.0;

+ 86 - 0
src/Materials/Textures/Procedurals/babylon.noiseProceduralTexture.ts

@@ -0,0 +1,86 @@
+module BABYLON {
+    /**
+     * Class used to generate noise procedural textures
+     */
+    export class NoiseProceduralTexture extends ProceduralTexture {
+        private _time = new Vector2();
+
+        /** Gets or sets a value between 0 and 1 indicating the overall brightness of the texture (default is 0.2) */
+        public brightness = 0.2;
+
+        /** Defines the first octave to start from (default is 3) */
+        public firstOctave = 3;
+
+        /** Defines the number of octaves to process */
+        public octaves = 8;
+
+        /** Defines the level of persistence (0.8 by default) */
+        public persistence = 0.8;
+
+        /** Gets or sets animation speed factor for X axis (default is 1) */
+        public animationSpeedFactorX = 1;
+
+        /** Gets or sets animation speed factor for Y axis (default is 1) */
+        public animationSpeedFactorY = 1;
+
+        /**
+         * Creates a new NoiseProceduralTexture
+         * @param name defines the name fo the texture
+         * @param size defines the size of the texture (default is 256)
+         * @param scene defines the hosting scene
+         * @param fallbackTexture defines the texture to use if the NoiseProceduralTexture can't be created
+         * @param generateMipMaps defines if mipmaps must be generated (true by default)
+         */
+        constructor(name: string, size: number = 256, scene: Nullable<Scene> = Engine.LastCreatedScene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+            super(name, size, "noise", scene, fallbackTexture, generateMipMaps);
+            this._updateShaderUniforms();
+        }
+
+        private _updateShaderUniforms() {
+            let scene = this.getScene();
+
+            if (!scene) {
+                return;
+            }
+
+            this._time.x += scene.getAnimationRatio() * this.animationSpeedFactorX * 0.001;
+            this._time.y += scene.getAnimationRatio() * this.animationSpeedFactorY * 0.001;
+
+            this.setFloat("brightness", this.brightness);
+            this.setInt("firstOctave", this.firstOctave);
+            this.setInt("octaves", this.octaves);
+            this.setFloat("persistence", this.persistence);
+            this.setVector2("timeScale", this._time);
+        }
+
+        /** Generate the current state of the procedural texture */
+        public render(useCameraPostProcess?: boolean) {
+            this._updateShaderUniforms();
+            super.render(useCameraPostProcess);
+        }
+
+        /**
+         * Serializes this noise procedural texture
+         * @returns a serialized noise procedural texture object
+         */
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this, super.serialize());
+            serializationObject.customType = "BABYLON.NoiseProceduralTexture";
+
+            return serializationObject;
+        }
+
+        /**
+         * Creates a NoiseProceduralTexture from parsed noise procedural texture data
+         * @param parsedTexture defines parsed texture data
+         * @param scene defines the current scene
+         * @param rootUrl defines the root URL containing noise procedural texture information
+         * @returns a parsed NoiseProceduralTexture
+         */
+        public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): NoiseProceduralTexture {
+            var texture = SerializationHelper.Parse(() => new NoiseProceduralTexture(parsedTexture.name, parsedTexture._size, scene, undefined, parsedTexture._generateMipMaps), parsedTexture, scene, rootUrl);
+
+            return texture;
+        }        
+    }
+}

+ 22 - 1
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -23,6 +23,7 @@
 
         public _textures: {[key: string]: Texture} = {};
         private _floats: {[key: string]: number} = {};
+        private _ints: {[key: string]: number} = {};
         private _floatsArrays: {[key: string]: number[]} = {};
         private _colors3: {[key: string]: Color3} = {};
         private _colors4: {[key: string]: Color4} = {};
@@ -35,9 +36,11 @@
         private _fallbackTextureUsed = false;
         private _engine: Engine;
 
-        constructor(name: string, size: any, fragment: any, scene: Scene, fallbackTexture: Nullable<Texture> = null, generateMipMaps = true, public isCube = false) {
+        constructor(name: string, size: any, fragment: any, scene: Nullable<Scene>, fallbackTexture: Nullable<Texture> = null, generateMipMaps = true, public isCube = false) {
             super(null, scene, !generateMipMaps);
 
+            scene = this.getScene()!;
+
             scene.proceduralTextures.push(this);
 
             this._engine = scene.getEngine();
@@ -232,6 +235,19 @@
             return this;
         }
 
+        /**
+         * Set the value of an uniform to an integer value
+         * @param name defines the name of the uniform
+         * @param value defines the value to set
+         * @returns the current procedural texture
+         */
+        public setInt(name: string, value: number): ProceduralTexture {
+            this._checkUniform(name);
+            this._ints[name] = value;
+
+            return this;
+        }
+
         public setFloats(name: string, value: number[]): ProceduralTexture {
             this._checkUniform(name);
             this._floatsArrays[name] = value;
@@ -293,6 +309,11 @@
             }
 
             // Float    
+            for (name in this._ints) {
+                this._effect.setInt(name, this._ints[name]);
+            }            
+
+            // Float    
             for (name in this._floats) {
                 this._effect.setFloat(name, this._floats[name]);
             }

+ 18 - 1
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -6,15 +6,32 @@ module BABYLON {
         private _pointerCaptures: {[pointerId:number]: boolean} = {};
         private _lastPointerEvents: {[pointerId:number]: number} = {};
         private static _DefaultUtilityLayer:Nullable<UtilityLayerRenderer> = null;
+        private static _DefaultKeepDepthUtilityLayer:Nullable<UtilityLayerRenderer> = null;
+        /** 
+         * A shared utility layer that can be used to overlay objects into a scene (Depth map of the previous scene is cleared before drawing on top of it)
+         */ 
         public static get DefaultUtilityLayer():UtilityLayerRenderer{
             if(UtilityLayerRenderer._DefaultUtilityLayer == null){
                 UtilityLayerRenderer._DefaultUtilityLayer = new UtilityLayerRenderer(BABYLON.Engine.LastCreatedScene!);
-                UtilityLayerRenderer._DefaultUtilityLayer.originalScene.onDisposeObservable.add(()=>{
+                UtilityLayerRenderer._DefaultUtilityLayer.originalScene.onDisposeObservable.addOnce(()=>{
                     UtilityLayerRenderer._DefaultUtilityLayer = null;
                 });
             }
             return UtilityLayerRenderer._DefaultUtilityLayer;
         }
+        /** 
+         * A shared utility layer that can be used to embed objects into a scene (Depth map of the previous scene is not cleared before drawing on top of it)
+         */ 
+        public static get DefaultKeepDepthUtilityLayer():UtilityLayerRenderer{
+            if(UtilityLayerRenderer._DefaultKeepDepthUtilityLayer == null){
+                UtilityLayerRenderer._DefaultKeepDepthUtilityLayer = new UtilityLayerRenderer(BABYLON.Engine.LastCreatedScene!);
+                UtilityLayerRenderer._DefaultKeepDepthUtilityLayer.utilityLayerScene.autoClearDepthAndStencil = false;
+                UtilityLayerRenderer._DefaultKeepDepthUtilityLayer.originalScene.onDisposeObservable.addOnce(()=>{
+                    UtilityLayerRenderer._DefaultKeepDepthUtilityLayer = null;
+                });
+            }
+            return UtilityLayerRenderer._DefaultKeepDepthUtilityLayer;
+        }
 
         /** 
          * The scene that is rendered on top of the original scene

+ 78 - 0
src/Shaders/noise.fragment.fx

@@ -0,0 +1,78 @@
+// Source: https://www.shadertoy.com/view/4lB3zz
+
+// Uniforms
+uniform float brightness;
+uniform int firstOctave;
+uniform int octaves;
+uniform float persistence;
+uniform vec2 timeScale;
+
+// Varyings
+varying vec2 vUV;
+
+// Functions
+float noise(int x,int y)
+{   
+    float fx = float(x);
+    float fy = float(y);
+    
+    return 2.0 * fract(sin(dot(vec2(fx, fy), vec2(12.9898, 78.233))) * 43758.5453) - 1.0;
+}
+
+float smoothNoise(int x,int y)
+{
+    return noise(x, y) / 4.0 + (noise(x + 1, y) + noise(x - 1,y) + 
+           noise(x, y + 1) + noise(x, y - 1)) / 8.0 + (noise(x + 1, y + 1) +
+           noise(x + 1,y - 1) + noise(x - 1, y + 1) + noise(x - 1,y - 1)) / 16.0;
+}
+
+float cosInterpolation(float x,float y,float n)
+{
+    float r = n * 3.1415926;
+    float f = (1.0 - cos(r)) * 0.5;
+    return x * (1.0 - f) + y * f;    
+}
+
+float interpolationNoise(float x, float y)
+{
+    int ix = int(x);
+    int iy = int(y);
+    float fracx = x - float(int(x));
+    float fracy = y - float(int(y));
+    
+    float v1 = smoothNoise(ix, iy);
+    float v2 = smoothNoise(ix + 1, iy);
+    float v3 = smoothNoise(ix, iy + 1);
+    float v4 = smoothNoise(ix + 1, iy + 1);
+    
+   	float i1 = cosInterpolation(v1, v2, fracx);
+    float i2 = cosInterpolation(v3, v4, fracx);
+    
+    return cosInterpolation(i1, i2, fracy);    
+}
+
+float perlinNoise2D(float x,float y)
+{
+    float sum = 0.0;
+    float frequency = 0.0;
+    float amplitude = 0.0;
+    for(int i = firstOctave; i < octaves + firstOctave; i++)
+    {
+        frequency = pow(2.0, float(i));
+        amplitude = pow(persistence, float(i));
+        sum = sum + interpolationNoise(x * frequency, y * frequency) * amplitude;
+    }
+    
+    return sum;
+}
+
+// Main
+void main(void)
+{
+    float x = abs(vUV.x + timeScale.x);
+    float y = abs(vUV.y + timeScale.y);
+
+    float noise = brightness + (1.0 - brightness) * perlinNoise2D(x,y);
+
+	gl_FragColor = vec4(noise, noise, noise, 1.0);
+}

+ 1 - 1
src/babylon.scene.ts

@@ -1513,7 +1513,7 @@
          * @returns a number
          */
         public getAnimationRatio(): number {
-            return this._animationRatio;
+            return this._animationRatio !== undefined ? this._animationRatio : 1;
         }
 
         /** 

二進制
tests/validation/ReferenceImages/Gizmos.png


二進制
tests/validation/ReferenceImages/spherepanel.png


+ 12 - 0
tests/validation/config.json

@@ -2,6 +2,18 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [  
     {
+      "title": "Gizmos",
+      "playgroundId": "#8GY6J8#48",
+      "renderCount": 50,
+      "referenceImage": "Gizmos.png"
+    }, 
+    {
+      "title": "GUI3D SpherePanel",
+      "playgroundId": "#HB4C01#9",
+      "renderCount": 50,
+      "referenceImage": "spherepanel.png"
+    },     
+    {
       "title": "Particle Helper",
       "playgroundId": "#1VGT5D#2",
       "renderCount": 50,