Selaa lähdekoodia

update from master

nockawa 9 vuotta sitten
vanhempi
commit
cf2f0b5d33
100 muutettua tiedostoa jossa 9020 lisäystä ja 4644 poistoa
  1. BIN
      Exporters/3ds Max/Max2Babylon-0.4.6.zip
  2. 64 59
      Exporters/FBX/BabylonFbxNative/BabylonMesh.cpp
  3. 2 0
      Exporters/FBX/readme.md
  4. 5 3
      Tools/Gulp/config.json
  5. 97 0
      Tools/Gulp/gulp-removeShaderComments.js
  6. 7 2
      Tools/Gulp/gulpfile.js
  7. 22 23
      dist/preview release/babylon.core.js
  8. 2277 2124
      dist/preview release/babylon.d.ts
  9. 29 29
      dist/preview release/babylon.js
  10. 1860 415
      dist/preview release/babylon.max.js
  11. 29 29
      dist/preview release/babylon.noworker.js
  12. 4 0
      dist/preview release/what's new.md
  13. 2 2
      materialsLibrary/dist/babylon.fireMaterial.js
  14. 1 1
      materialsLibrary/dist/babylon.fireMaterial.min.js
  15. 2 2
      materialsLibrary/dist/babylon.furMaterial.js
  16. 1 1
      materialsLibrary/dist/babylon.furMaterial.min.js
  17. 2 2
      materialsLibrary/dist/babylon.gradientMaterial.js
  18. 1 1
      materialsLibrary/dist/babylon.gradientMaterial.min.js
  19. 2 2
      materialsLibrary/dist/babylon.lavaMaterial.js
  20. 1 1
      materialsLibrary/dist/babylon.lavaMaterial.min.js
  21. 2 2
      materialsLibrary/dist/babylon.normalMaterial.js
  22. 1 1
      materialsLibrary/dist/babylon.normalMaterial.min.js
  23. 45 8
      materialsLibrary/dist/babylon.pbrMaterial.js
  24. 3 3
      materialsLibrary/dist/babylon.pbrMaterial.min.js
  25. 2 2
      materialsLibrary/dist/babylon.simpleMaterial.js
  26. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.min.js
  27. 29 10
      materialsLibrary/dist/babylon.skyMaterial.js
  28. 1 1
      materialsLibrary/dist/babylon.skyMaterial.min.js
  29. 2 2
      materialsLibrary/dist/babylon.terrainMaterial.js
  30. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.min.js
  31. 2 2
      materialsLibrary/dist/babylon.triPlanarMaterial.js
  32. 1 1
      materialsLibrary/dist/babylon.triPlanarMaterial.min.js
  33. 2 2
      materialsLibrary/dist/babylon.waterMaterial.js
  34. 1 1
      materialsLibrary/dist/babylon.waterMaterial.min.js
  35. 3 0
      materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts
  36. 3 1
      materialsLibrary/dist/dts/babylon.skyMaterial.d.ts
  37. 97 0
      materialsLibrary/gulp-removeShaderComments.js
  38. 4 1
      materialsLibrary/gulpfile.js
  39. 10 9
      materialsLibrary/materials/gradient/gradient.fragment.fx
  40. 9 8
      materialsLibrary/materials/lava/lava.fragment.fx
  41. 9 8
      materialsLibrary/materials/normal/normal.fragment.fx
  42. 44 4
      materialsLibrary/materials/pbr/babylon.pbrMaterial.ts
  43. 4 4
      materialsLibrary/materials/pbr/legacypbr.fragment.fx
  44. 60 20
      materialsLibrary/materials/pbr/pbr.fragment.fx
  45. 9 8
      materialsLibrary/materials/simple/simple.fragment.fx
  46. 27 9
      materialsLibrary/materials/sky/babylon.skyMaterial.ts
  47. 4 4
      materialsLibrary/materials/sky/sky.fragment.fx
  48. 3 0
      materialsLibrary/test/add/addpbr.js
  49. 2683 1084
      materialsLibrary/test/refs/babylon.max.js
  50. 17 0
      src/Animations/babylon.animatable.js
  51. 21 0
      src/Animations/babylon.animatable.ts
  52. 94 5
      src/Animations/babylon.animation.js
  53. 109 6
      src/Animations/babylon.animation.ts
  54. 1 0
      src/Bones/babylon.bone.js
  55. 1 0
      src/Bones/babylon.bone.ts
  56. 2 2
      src/Cameras/VR/babylon.webVRCamera.js
  57. 5 4
      src/Cameras/VR/babylon.webVRCamera.ts
  58. 5 5
      src/Cameras/babylon.arcRotateCamera.js
  59. 5 6
      src/Cameras/babylon.arcRotateCamera.ts
  60. 2 2
      src/Cameras/babylon.camera.js
  61. 2 2
      src/Cameras/babylon.camera.ts
  62. 5 5
      src/Cameras/babylon.targetCamera.js
  63. 7 7
      src/Cameras/babylon.targetCamera.ts
  64. 1 1
      src/Culling/babylon.boundingBox.js
  65. 1 1
      src/Culling/babylon.boundingBox.ts
  66. 1 1
      src/Culling/babylon.boundingSphere.js
  67. 1 1
      src/Culling/babylon.boundingSphere.ts
  68. 171 0
      src/Culling/babylon.ray.js
  69. 208 0
      src/Culling/babylon.ray.ts
  70. 35 1
      src/Debug/babylon.debugLayer.js
  71. 44 1
      src/Debug/babylon.debugLayer.ts
  72. 137 0
      src/Debug/babylon.skeletonViewer.js
  73. 140 0
      src/Debug/babylon.skeletonViewer.ts
  74. 24 11
      src/Layer/babylon.layer.js
  75. 36 11
      src/Layer/babylon.layer.ts
  76. 1 1
      src/LensFlare/babylon.lensFlareSystem.js
  77. 1 1
      src/LensFlare/babylon.lensFlareSystem.ts
  78. 4 1
      src/Lights/babylon.light.js
  79. 5 1
      src/Lights/babylon.light.ts
  80. 3 0
      src/Loading/Plugins/babylon.babylonFileLoader.js
  81. 4 0
      src/Loading/Plugins/babylon.babylonFileLoader.ts
  82. 19 7
      src/Materials/Textures/babylon.hdrCubeTexture.js
  83. 31 7
      src/Materials/Textures/babylon.hdrcubetexture.ts
  84. 23 6
      src/Materials/babylon.effect.js
  85. 26 8
      src/Materials/babylon.effect.ts
  86. 80 267
      src/Math/babylon.math.js
  87. 87 324
      src/Math/babylon.math.ts
  88. 4 4
      src/Mesh/babylon.abstractMesh.js
  89. 4 4
      src/Mesh/babylon.abstractMesh.ts
  90. 2 2
      src/Mesh/babylon.mesh.js
  91. 2 2
      src/Mesh/babylon.mesh.ts
  92. 1 1
      src/Mesh/babylon.meshSimplification.js
  93. 1 1
      src/Mesh/babylon.meshSimplification.ts
  94. 3 0
      src/Particles/babylon.particleSystem.js
  95. 4 0
      src/Particles/babylon.particleSystem.ts
  96. 52 17
      src/Physics/Plugins/babylon.cannonJSPlugin.js
  97. 59 22
      src/Physics/Plugins/babylon.cannonJSPlugin.ts
  98. 26 1
      src/Physics/Plugins/babylon.oimoJSPlugin.js
  99. 33 2
      src/Physics/Plugins/babylon.oimoJSPlugin.ts
  100. 0 0
      src/Physics/babylon.physicsEngine.js

BIN
Exporters/3ds Max/Max2Babylon-0.4.6.zip


+ 64 - 59
Exporters/FBX/BabylonFbxNative/BabylonMesh.cpp

@@ -440,77 +440,82 @@ BabylonMesh::BabylonMesh(BabylonNode* node) :
 	}
 	pivotMatrix = ConvertToBabylonCoordinateSystem( GetGeometryTransformation(fbxNode));
 
-	auto animStack = fbxNode->GetScene()->GetCurrentAnimationStack();
-	FbxString animStackName = animStack->GetName();
-	//FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
-	auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
-	auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
-	auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
-	auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
-	auto animLengthInFrame = endFrame - startFrame + 1;
-	_visibility = static_cast<float>(node->fbxNode()->Visibility.Get());
-	auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true);
-	auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true);
 	auto mesh = fbxNode->GetMesh();
-	_isVisible = fbxNode->Show.Get();
-	
-	auto rotCurveNode = fbxNode->LclRotation.GetCurveNode();
-	auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode();
-	auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode();
-	auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode();
-	if (rotCurveNode || translateCurveNode || scalingCurveNode) {
-		for (auto ix = 0; ix < animLengthInFrame; ix++) {
-			FbxTime currTime;
-			currTime.SetFrame(startFrame + ix, animTimeMode);
-
-			babylon_animation_key<babylon_vector3> poskey;
-			babylon_animation_key<babylon_vector4> rotkey;
-			babylon_animation_key<babylon_vector3> scalekey;
-			poskey.frame = ix;
-			rotkey.frame = ix;
-			scalekey.frame = ix;
-			auto currTransform = node->GetLocal(currTime);
-			poskey.values = currTransform.translation();
-			rotkey.values = currTransform.rotationQuaternion();
-			scalekey.values = currTransform.scaling();
-			posAnim->appendKey(poskey);
-			rotAnim->appendKey(rotkey);
-			scaleAnim->appendKey(scalekey);
+	auto animStack = fbxNode->GetScene()->GetCurrentAnimationStack();
 
+	if (animStack) {
+		FbxString animStackName = animStack->GetName();
+		//FbxTakeInfo* takeInfo = node->GetScene()->GetTakeInfo(animStackName);
+		auto animTimeMode = GlobalSettings::Current().AnimationsTimeMode;
+		auto animFrameRate = GlobalSettings::Current().AnimationsFrameRate();
+		auto startFrame = animStack->GetLocalTimeSpan().GetStart().GetFrameCount(animTimeMode);
+		auto endFrame = animStack->GetLocalTimeSpan().GetStop().GetFrameCount(animTimeMode);
+		auto animLengthInFrame = endFrame - startFrame + 1;
+		_visibility = static_cast<float>(node->fbxNode()->Visibility.Get());
+		auto posAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"position", L"position", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto rotAnim = std::make_shared<BabylonAnimation<babylon_vector4>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"rotationQuaternion", L"rotationQuaternion", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto scaleAnim = std::make_shared<BabylonAnimation<babylon_vector3>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"scaling", L"scaling", true, 0, static_cast<int>(animLengthInFrame), true);
+		auto visibilityAnim = std::make_shared<BabylonAnimation<float>>(BabylonAnimationBase::loopBehavior_Cycle, static_cast<int>(animFrameRate), L"visibility", L"visibility", true, 0, static_cast<int>(animLengthInFrame), true);
+
+		_isVisible = fbxNode->Show.Get();
+
+		auto rotCurveNode = fbxNode->LclRotation.GetCurveNode();
+		auto translateCurveNode = fbxNode->LclTranslation.GetCurveNode();
+		auto scalingCurveNode = fbxNode->LclScaling.GetCurveNode();
+		auto visibilityCurveNode = fbxNode->Visibility.GetCurveNode();
+		if (rotCurveNode || translateCurveNode || scalingCurveNode) {
+			for (auto ix = 0; ix < animLengthInFrame; ix++) {
+				FbxTime currTime;
+				currTime.SetFrame(startFrame + ix, animTimeMode);
+
+				babylon_animation_key<babylon_vector3> poskey;
+				babylon_animation_key<babylon_vector4> rotkey;
+				babylon_animation_key<babylon_vector3> scalekey;
+				poskey.frame = ix;
+				rotkey.frame = ix;
+				scalekey.frame = ix;
+				auto currTransform = node->GetLocal(currTime);
+				poskey.values = currTransform.translation();
+				rotkey.values = currTransform.rotationQuaternion();
+				scalekey.values = currTransform.scaling();
+				posAnim->appendKey(poskey);
+				rotAnim->appendKey(rotkey);
+				scaleAnim->appendKey(scalekey);
 
+
+			}
 		}
-	}
-	if (visibilityCurveNode) {
-		for (auto ix = 0; ix < animLengthInFrame; ix++) {
-			FbxTime currTime;
-			currTime.SetFrame(startFrame + ix, animTimeMode);
+		if (visibilityCurveNode) {
+			for (auto ix = 0; ix < animLengthInFrame; ix++) {
+				FbxTime currTime;
+				currTime.SetFrame(startFrame + ix, animTimeMode);
 
-			babylon_animation_key<float> visibilityKey;
+				babylon_animation_key<float> visibilityKey;
 
-			visibilityKey.frame = ix;
+				visibilityKey.frame = ix;
 
-			visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime));
+				visibilityKey.values = static_cast<float>(node->fbxNode()->Visibility.EvaluateValue(currTime));
 
-			visibilityAnim->appendKey(visibilityKey);
+				visibilityAnim->appendKey(visibilityKey);
 
 
+			}
+		}
+
+		if (!posAnim->isConstant()){
+			animations.push_back(posAnim);
+		}
+		if (!rotAnim->isConstant()){
+			animations.push_back(rotAnim);
+		}
+		if (!scaleAnim->isConstant()){
+			animations.push_back(scaleAnim);
+		}
+		if (!visibilityAnim->isConstant()) {
+			animations.push_back(visibilityAnim);
 		}
 	}
-	
-	if (!posAnim->isConstant()){
-		animations.push_back(posAnim);
-	}
-	if (!rotAnim->isConstant()){
-		animations.push_back(rotAnim);
-	}
-	if (!scaleAnim->isConstant()){
-		animations.push_back(scaleAnim);
-	}
-	if (!visibilityAnim->isConstant()) {
-		animations.push_back(visibilityAnim);
-	}
+
 	if (!mesh) {
 		return;
 	}

+ 2 - 0
Exporters/FBX/readme.md

@@ -11,6 +11,8 @@ FBX Exporter produces a babylon scene file from an FBX asset
 
 ##Prerequisites
 To use this tool, you need to download the Visual C++ 2015 redistribuable package : http://www.microsoft.com/en-us/download/details.aspx?id=48145
+
+To build from source you need to install the Autodesk FBX SDK 2016.1 and copy the lib folder from the SDK install location to 3rdParty\Fbx2016.1\
 ##Usage
 FbxExporter.exe "fbx file" "outdir" [/fps:60|30|24] [/skipemptynodes]
 - fbx file : path to the source FBX asset

+ 5 - 3
Tools/Gulp/config.json

@@ -22,8 +22,8 @@
       "../../src/Tools/babylon.smartArray.js",
       "../../src/Tools/babylon.smartCollection.js",
       "../../src/Tools/babylon.tools.js",      
-      "../../src/states/babylon.alphaCullingState.js",
-      "../../src/states/babylon.depthCullingState.js",
+      "../../src/States/babylon.alphaCullingState.js",
+      "../../src/States/babylon.depthCullingState.js",
       "../../src/babylon.engine.js",
       "../../src/babylon.node.js",
       "../../src/Tools/babylon.filesInput.js",
@@ -31,6 +31,7 @@
       "../../src/Culling/babylon.boundingSphere.js",
       "../../src/Culling/babylon.boundingBox.js",
       "../../src/Culling/babylon.boundingInfo.js",
+      "../../src/Culling/babylon.ray.js",
       "../../src/Mesh/babylon.abstractMesh.js",
       "../../src/Lights/babylon.light.js",
       "../../src/Lights/babylon.pointLight.js",
@@ -191,7 +192,8 @@
       "../../src/tools/hdr/babylon.tools.panoramatocubemap.js",
       "../../src/tools/hdr/babylon.tools.hdr.js",
       "../../src/tools/hdr/babylon.tools.pmremGenerator.js",
-      "../../src/materials/textures/babylon.hdrcubetexture.js"
+      "../../src/materials/textures/babylon.hdrcubetexture.js",
+      "../../src/debug/babylon.skeletonViewer.js"
     ]
   }
 }

+ 97 - 0
Tools/Gulp/gulp-removeShaderComments.js

@@ -0,0 +1,97 @@
+'use strict';
+
+var through = require('through2');
+var PluginError = require('gulp-util').PluginError;
+var singleComment = 1;
+var multiComment = 2;
+
+function uncomment(str, opts) {
+    opts = opts || {};
+
+	var currentChar;
+	var nextChar;
+	var insideString = false;
+	var insideComment = 0;
+	var offset = 0;
+	var ret = '';
+
+    str = str.replace(/\r\n/g, '\n');
+    str = str.replace(/[ \f\t\v]+/g, ' ');
+    str = str.replace(/^\s*\n/gm, '');
+    str = str.replace(/ \+ /g, '+');
+    str = str.replace(/ \- /g, '-');
+    str = str.replace(/ \/ /g, '/');
+    str = str.replace(/ \* /g, '*');
+    str = str.replace(/ > /g, '>');
+    str = str.replace(/ < /g, '<');
+    str = str.replace(/ >= /g, '>=');
+    str = str.replace(/ <= /g, '<=');
+    str = str.replace(/ \+= /g, '+=');
+    str = str.replace(/ \-= /g, '-=');
+    str = str.replace(/ \/= /g, '/=');
+    str = str.replace(/ \*= /g, '*=');
+    str = str.replace(/ = /g, '=');
+    str = str.replace(/, /g, ',');
+    str = str.replace(/\n\n/g, '\n');
+    str = str.replace(/\n /g, '\n');
+    
+	for (var i = 0; i < str.length; i++) {
+		currentChar = str[i];
+		nextChar = str[i + 1];
+
+		if (!insideComment && currentChar === '"') {
+			var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+			if (!escaped) {
+				insideString = !insideString;
+			}
+		}
+
+		if (insideString) {
+			continue;
+		}
+
+		if (!insideComment && currentChar + nextChar === '//') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = singleComment;
+			i++;
+		} else if (insideComment === singleComment && currentChar === '\n') {
+			insideComment = 0;
+			offset = i;
+		} else if (!insideComment && currentChar + nextChar === '/*') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = multiComment;
+			i++;
+			continue;
+		} else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+			i++;
+			insideComment = 0;
+			offset = i + 1;
+			continue;
+		}
+	}
+
+	return ret + (insideComment ? '' : str.substr(offset));
+}
+
+function gulpUncomment(options) {
+    return main(options, uncomment);
+}
+
+function main(options, func) {
+    return through.obj(function (file, enc, cb) {
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+        if (file.isStream()) {
+            cb(new PluginError("Remove Shader Comments", "Streaming not supported."));
+        }
+        file.contents = new Buffer(func(file.contents.toString(), options));
+        this.push(file);
+        return cb();
+    });
+}
+
+module.exports = gulpUncomment;

+ 7 - 2
Tools/Gulp/gulpfile.js

@@ -11,6 +11,7 @@ var cleants = require('gulp-clean-ts-extends');
 var changed = require('gulp-changed');
 var runSequence = require('run-sequence');
 var replace = require("gulp-replace");
+var uncommentShader = require("./gulp-removeShaderComments");
 
 var config = require("./config.json");
 
@@ -33,7 +34,9 @@ function includeShadersName(filename) {
 
 gulp.task("includeShaders", function (cb) {
     includeShadersStream = config.includeShadersDirectories.map(function (shadersDef) {
-        return gulp.src(shadersDef.files).pipe(srcToVariable({
+        return gulp.src(shadersDef.files).
+            pipe(uncommentShader()).
+            pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: includeShadersName
         }));
     });
@@ -42,7 +45,9 @@ gulp.task("includeShaders", function (cb) {
 
 gulp.task("shaders", ["includeShaders"], function (cb) {
     shadersStream = config.shadersDirectories.map(function (shadersDef) {
-        return gulp.src(shadersDef.files).pipe(srcToVariable({
+        return gulp.src(shadersDef.files).
+            pipe(uncommentShader()).
+            pipe(srcToVariable({
             variableName: shadersDef.variable, asMap: true, namingCallback: shadersName
         }));
     });

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 22 - 23
dist/preview release/babylon.core.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2277 - 2124
dist/preview release/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 29 - 29
dist/preview release/babylon.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1860 - 415
dist/preview release/babylon.max.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 29 - 29
dist/preview release/babylon.noworker.js


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

@@ -6,7 +6,11 @@
     - new mesh type : `LineSystem` ([jerome](https://github.com/jbousquie))
     - SerializationHelper for complex classes using TypeScript decorators  ([deltakosh](https://github.com/deltakosh))
     - StandardMaterial now supports Parallax and Parallax Occlusion Mapping ([nockawa](https://github.com/nockawa))
+    - Animations blending. See [demo here](http://www.babylonjs-playground.com/#2BLI9T#3). More [info here](NEED DOC!) ([deltakosh](https://github.com/deltakosh))
+    - New debuger tool: SkeletonViewer. See [demo here](Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
   - **Updates**
+    - Support for Layer.alphaTest ([deltakosh](https://github.com/deltakosh))
+    - New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection ([deltakosh](https://github.com/deltakosh))
     - New OnPickTrigger support for spritesManager ([deltakosh](https://github.com/deltakosh))
     - New SPS method `digest()` ([jerome](https://github.com/jbousquie))    
     - New SPS property `computeBoundingBox` ([jerome](https://github.com/jbousquie))  

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.fireMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.furMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.furMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.gradientMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.gradientMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.lavaMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.lavaMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.normalMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 45 - 8
materialsLibrary/dist/babylon.pbrMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3 - 3
materialsLibrary/dist/babylon.pbrMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.simpleMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 29 - 10
materialsLibrary/dist/babylon.skyMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.skyMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.terrainMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.triPlanarMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.triPlanarMaterial.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2 - 2
materialsLibrary/dist/babylon.waterMaterial.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 1
materialsLibrary/dist/babylon.waterMaterial.min.js


+ 3 - 0
materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts

@@ -58,6 +58,9 @@ declare module BABYLON {
         useScalarInLinearSpace: boolean;
         usePhysicalLightFalloff: boolean;
         useRadianceOverAlpha: boolean;
+        useParallax: boolean;
+        useParallaxOcclusion: boolean;
+        parallaxScaleBias: number;
         disableLighting: boolean;
         private _renderTargets;
         private _worldViewProjectionMatrix;

+ 3 - 1
materialsLibrary/dist/dts/babylon.skyMaterial.d.ts

@@ -9,7 +9,9 @@ declare module BABYLON {
         distance: number;
         inclination: number;
         azimuth: number;
-        private _sunPosition;
+        sunPosition: Vector3;
+        useSunPosition: boolean;
+        private _cameraPosition;
         private _renderId;
         private _defines;
         private _cachedDefines;

+ 97 - 0
materialsLibrary/gulp-removeShaderComments.js

@@ -0,0 +1,97 @@
+'use strict';
+
+var through = require('through2');
+var PluginError = require('gulp-util').PluginError;
+var singleComment = 1;
+var multiComment = 2;
+
+function uncomment(str, opts) {
+    opts = opts || {};
+
+	var currentChar;
+	var nextChar;
+	var insideString = false;
+	var insideComment = 0;
+	var offset = 0;
+	var ret = '';
+
+    str = str.replace(/\r\n/g, '\n');
+    str = str.replace(/[ \f\t\v]+/g, ' ');
+    str = str.replace(/^\s*\n/gm, '');
+    str = str.replace(/ \+ /g, '+');
+    str = str.replace(/ \- /g, '-');
+    str = str.replace(/ \/ /g, '/');
+    str = str.replace(/ \* /g, '*');
+    str = str.replace(/ > /g, '>');
+    str = str.replace(/ < /g, '<');
+    str = str.replace(/ >= /g, '>=');
+    str = str.replace(/ <= /g, '<=');
+    str = str.replace(/ \+= /g, '+=');
+    str = str.replace(/ \-= /g, '-=');
+    str = str.replace(/ \/= /g, '/=');
+    str = str.replace(/ \*= /g, '*=');
+    str = str.replace(/ = /g, '=');
+    str = str.replace(/, /g, ',');
+    str = str.replace(/\n\n/g, '\n');
+    str = str.replace(/\n /g, '\n');
+    
+	for (var i = 0; i < str.length; i++) {
+		currentChar = str[i];
+		nextChar = str[i + 1];
+
+		if (!insideComment && currentChar === '"') {
+			var escaped = str[i - 1] === '\\' && str[i - 2] !== '\\';
+			if (!escaped) {
+				insideString = !insideString;
+			}
+		}
+
+		if (insideString) {
+			continue;
+		}
+
+		if (!insideComment && currentChar + nextChar === '//') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = singleComment;
+			i++;
+		} else if (insideComment === singleComment && currentChar === '\n') {
+			insideComment = 0;
+			offset = i;
+		} else if (!insideComment && currentChar + nextChar === '/*') {
+			ret += str.slice(offset, i);
+			offset = i;
+			insideComment = multiComment;
+			i++;
+			continue;
+		} else if (insideComment === multiComment && currentChar + nextChar === '*/') {
+			i++;
+			insideComment = 0;
+			offset = i + 1;
+			continue;
+		}
+	}
+
+	return ret + (insideComment ? '' : str.substr(offset));
+}
+
+function gulpUncomment(options) {
+    return main(options, uncomment);
+}
+
+function main(options, func) {
+    return through.obj(function (file, enc, cb) {
+        if (file.isNull()) {
+            cb(null, file);
+            return;
+        }
+        if (file.isStream()) {
+            cb(new PluginError("Remove Shader Comments", "Streaming not supported."));
+        }
+        file.contents = new Buffer(func(file.contents.toString(), options));
+        this.push(file);
+        return cb();
+    });
+}
+
+module.exports = gulpUncomment;

+ 4 - 1
materialsLibrary/gulpfile.js

@@ -8,6 +8,7 @@ var cleants = require('gulp-clean-ts-extends');
 var replace = require("gulp-replace");
 var webserver = require('gulp-webserver');
 var uglify = require("gulp-uglify");
+var uncommentShader = require("./gulp-removeShaderComments");
 
 var config = require("./config.json");
 var extendsSearchRegex = /var\s__extends[\s\S]+?\};/g;
@@ -52,7 +53,9 @@ gulp.task('default', ["copyReference"], function () {
                 .pipe(gulp.dest(config.build.dtsOutputDirectory));
         }
         
-        var shader = gulp.src(material.shaderFiles).pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
+        var shader = gulp.src(material.shaderFiles)
+                .pipe(uncommentShader())
+                .pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
 
         return merge2(js, shader)
             .pipe(cleants())

+ 10 - 9
materialsLibrary/materials/gradient/gradient.fragment.fx

@@ -23,10 +23,10 @@ varying vec4 vColor;
 
 // Lights
 
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 
 #include<lightsFragmentFunctions>
@@ -79,13 +79,14 @@ void main(void) {
 
 	// Lighting
 	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
 	float shadow = 1.;
     float glossiness = 0.;
     
-#include<light0Fragment>
-#include<light1Fragment>
-#include<light2Fragment>
-#include<light3Fragment>
+#include<lightFragment>[0]
+#include<lightFragment>[1]
+#include<lightFragment>[2]
+#include<lightFragment>[3]
 
 #ifdef VERTEXALPHA
 	alpha *= vColor.a;
@@ -99,4 +100,4 @@ void main(void) {
 #include<fogFragment>
 
 	gl_FragColor = color;
-}
+}

+ 9 - 8
materialsLibrary/materials/lava/lava.fragment.fx

@@ -27,10 +27,10 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 
 #include<lightsFragmentFunctions>
@@ -121,13 +121,14 @@ void main(void) {
 
 	// Lighting
 	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
 	float shadow = 1.;
     float glossiness = 0.;
     
-#include<light0Fragment>
-#include<light1Fragment>
-#include<light2Fragment>
-#include<light3Fragment>
+#include<lightFragment>[0]
+#include<lightFragment>[1]
+#include<lightFragment>[2]
+#include<lightFragment>[3]
 
 
 #ifdef VERTEXALPHA

+ 9 - 8
materialsLibrary/materials/normal/normal.fragment.fx

@@ -16,10 +16,10 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 
 #include<lightsFragmentFunctions>
@@ -77,13 +77,14 @@ void main(void) {
 
 	// Lighting
 	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
 	float shadow = 1.;
     float glossiness = 0.;
     
-#include<light0Fragment>
-#include<light1Fragment>
-#include<light2Fragment>
-#include<light3Fragment>
+#include<lightFragment>[0]
+#include<lightFragment>[1]
+#include<lightFragment>[2]
+#include<lightFragment>[3]
 
 
 #ifdef VERTEXALPHA

+ 44 - 4
materialsLibrary/materials/pbr/babylon.pbrMaterial.ts

@@ -12,6 +12,8 @@ module BABYLON {
         public EMISSIVE = false;
         public REFLECTIVITY = false;
         public BUMP = false;
+        public PARALLAX = false;
+        public PARALLAXOCCLUSION = false;
         public SPECULAROVERALPHA = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
@@ -91,6 +93,8 @@ module BABYLON {
         public LODBASEDMICROSFURACE = false;
         public USEPHYSICALLIGHTFALLOFF = false;
         public RADIANCEOVERALPHA = false;
+        public USEPMREMREFLECTION = false;
+        public USEPMREMREFRACTION = false;
 
         constructor() {
             super();
@@ -266,6 +270,15 @@ module BABYLON {
         public useRadianceOverAlpha = true;
         
         @serialize()
+        public useParallax = false;
+
+        @serialize()
+        public useParallaxOcclusion = false;
+
+        @serialize()
+        public parallaxScaleBias = 0.05;
+        
+        @serialize()
         public disableLighting = false;
         
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
@@ -517,6 +530,10 @@ module BABYLON {
                             if (this.reflectionTexture instanceof HDRCubeTexture && (<HDRCubeTexture>this.reflectionTexture)) {
                                 this._defines.USESPHERICALFROMREFLECTIONMAP = true;
                                 needNormals = true;
+                                
+                                if ((<HDRCubeTexture>this.reflectionTexture).isPMREM) {
+                                    this._defines.USEPMREMREFLECTION = true;
+                                }
                             }
                         }
                     }
@@ -558,6 +575,13 @@ module BABYLON {
                     } else {
                         needUVs = true;
                         this._defines.BUMP = true;
+                        
+                        if (this.useParallax) {
+                            this._defines.PARALLAX = true;
+                            if (this.useParallaxOcclusion) {
+                                this._defines.PARALLAXOCCLUSION = true;
+                            }
+                        }
                     }
                 }
 
@@ -574,6 +598,10 @@ module BABYLON {
                         }
                         if (this.refractionTexture instanceof HDRCubeTexture) {
                             this._defines.REFRACTIONMAPINLINEARSPACE = true;
+                            
+                            if ((<HDRCubeTexture>this.refractionTexture).isPMREM) {
+                                this._defines.USEPMREMREFRACTION = true;
+                            }
                         }
                     }
                 }
@@ -712,6 +740,10 @@ module BABYLON {
                 if (this._defines.REFLECTION) {
                     fallbacks.addFallback(0, "REFLECTION");
                 }
+                
+                if (this._defines.REFRACTION) {
+                    fallbacks.addFallback(0, "REFRACTION");
+                }
 
                 if (this._defines.REFLECTIVITY) {
                     fallbacks.addFallback(0, "REFLECTIVITY");
@@ -720,6 +752,14 @@ module BABYLON {
                 if (this._defines.BUMP) {
                     fallbacks.addFallback(0, "BUMP");
                 }
+                
+                if (this._defines.PARALLAX) {
+                    fallbacks.addFallback(1, "PARALLAX");
+                }
+
+                if (this._defines.PARALLAXOCCLUSION) {
+                    fallbacks.addFallback(0, "PARALLAXOCCLUSION");
+                }
 
                 if (this._defines.SPECULAROVERALPHA) {
                     fallbacks.addFallback(0, "SPECULAROVERALPHA");
@@ -897,7 +937,7 @@ module BABYLON {
                     }
 
                     if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
-                        this._microsurfaceTextureLods.x = Math.log(this.reflectionTexture.getSize().width) * Math.LOG2E;
+                        this._microsurfaceTextureLods.x = Math.round(Math.log(this.reflectionTexture.getSize().width) * Math.LOG2E);
                         
                         if (this.reflectionTexture.isCube) {
                             this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
@@ -963,12 +1003,12 @@ module BABYLON {
                     if (this.bumpTexture && this._myScene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled && !this.disableBumpMap) {
                         this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-                        this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
+                        this._effect.setFloat3("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level, this.parallaxScaleBias);
                         this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
                     }
 
                     if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
-                        this._microsurfaceTextureLods.y = Math.log(this.refractionTexture.getSize().width) * Math.LOG2E;
+                        this._microsurfaceTextureLods.y = Math.round(Math.log(this.refractionTexture.getSize().width) * Math.LOG2E);
                         
                         var depth = 1.0;
                         if (this.refractionTexture.isCube) {
@@ -984,7 +1024,7 @@ module BABYLON {
                         this._effect.setFloat4("vRefractionInfos", this.refractionTexture.level, this.indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
                     }
                     
-                    if ((this.reflectionTexture || this.refractionTexture) && this._myScene.getEngine().getCaps().textureLOD) {
+                    if ((this.reflectionTexture || this.refractionTexture)) {
                         this._effect.setFloat2("vMicrosurfaceTextureLods", this._microsurfaceTextureLods.x, this._microsurfaceTextureLods.y);
                     }
                 }

+ 4 - 4
materialsLibrary/materials/pbr/legacypbr.fragment.fx

@@ -189,10 +189,10 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 // Samplers
 #ifdef ALBEDO

+ 60 - 20
materialsLibrary/materials/pbr/pbr.fragment.fx

@@ -72,7 +72,7 @@ uniform vec4 vCameraInfos;
     }
 #endif
 
-#ifdef LODBASEDMICROSFURACE
+#if defined(REFLECTION) || defined(REFRACTION)
     uniform vec2 vMicrosurfaceTextureLods;
 #endif
 
@@ -172,6 +172,14 @@ float getMipMapIndexFromAverageSlope(float maxMipLevel, float alpha)
     return clamp(mip, 0., maxMipLevel);
 }
 
+float getMipMapIndexFromAverageSlopeWithPMREM(float maxMipLevel, float alphaG)
+{
+    float specularPower = clamp(2. / alphaG - 2., 0.000001, 2048.);
+    
+    // Based on CubeMapGen for cosine power with 2048 spec default and 0.25 dropoff 
+    return clamp(- 0.5 * log2(specularPower) + 5.5, 0., maxMipLevel);
+}
+
 // From Microfacet Models for Refraction through Rough Surfaces, Walter et al. 2007
 float smithVisibilityG1_TrowbridgeReitzGGX(float dot, float alphaG)
 {
@@ -335,10 +343,10 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 // Samplers
 #ifdef ALBEDO
@@ -794,12 +802,8 @@ void main(void) {
     #else
         vec3 normalW = vec3(1.0, 1.0, 1.0);
     #endif
-
-
-    #ifdef BUMP
-		mat3 TBN = cotangent_frame(vNormalW * vBumpInfos.y, -viewDirectionW, vBumpUV);
-		normalW = perturbNormal(viewDirectionW, TBN, vBumpUV);
-    #endif
+    
+    #include<bumpFragment>
 
     // Ambient color
     vec3 ambientColor = vec3(1., 1., 1.);
@@ -1074,15 +1078,19 @@ vec3 surfaceRefractionColor = vec3(0., 0., 0.);
 // Go mat -> blurry reflexion according to microSurface
 #ifdef LODBASEDMICROSFURACE
     float alphaG = convertRoughnessToAverageSlope(roughness);
-#else
-    float bias = 20. * (1.0 - microSurface);
 #endif
         
 #ifdef REFRACTION
-	vec3 refractionVector = normalize(refract(-viewDirectionW, normalW, vRefractionInfos.y));
+	vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
     
     #ifdef LODBASEDMICROSFURACE
-        float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+        #ifdef USEPMREMREFRACTION
+            float lodRefraction = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.y, alphaG);
+        #else
+            float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+        #endif
+    #else
+        float biasRefraction = (vMicrosurfaceTextureLods.y + 2.) * (1.0 - microSurface);
     #endif
     
     #ifdef REFRACTIONMAP_3D
@@ -1091,9 +1099,22 @@ vec3 surfaceRefractionColor = vec3(0., 0., 0.);
         if (dot(refractionVector, viewDirectionW) < 1.0)
         {
             #ifdef LODBASEDMICROSFURACE
+                #ifdef USEPMREMREFRACTION
+                    // Empiric Threshold
+                    if (microSurface > 0.5)
+                    {
+                        // Bend to not reach edges.
+                        float scaleRefraction = 1. - exp2(lodRefraction) / exp2(vMicrosurfaceTextureLods.y); // CubemapSize is the size of the base mipmap
+                        float maxRefraction = max(max(abs(refractionVector.x), abs(refractionVector.y)), abs(refractionVector.z));
+                        if (abs(refractionVector.x) != maxRefraction) refractionVector.x *= scaleRefraction;
+                        if (abs(refractionVector.y) != maxRefraction) refractionVector.y *= scaleRefraction;
+                        if (abs(refractionVector.z) != maxRefraction) refractionVector.z *= scaleRefraction;
+                    }
+                #endif
+                
                 surfaceRefractionColor = textureCubeLodEXT(refractionCubeSampler, refractionVector, lodRefraction).rgb * vRefractionInfos.x;
             #else
-                surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, bias).rgb * vRefractionInfos.x;
+                surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, biasRefraction).rgb * vRefractionInfos.x;
             #endif
         }
         
@@ -1110,7 +1131,7 @@ vec3 surfaceRefractionColor = vec3(0., 0., 0.);
         #ifdef LODBASEDMICROSFURACE
             surfaceRefractionColor = texture2DLodEXT(refraction2DSampler, refractionCoords, lodRefraction).rgb * vRefractionInfos.x;
         #else
-            surfaceRefractionColor = texture2D(refraction2DSampler, refractionCoords, bias).rgb * vRefractionInfos.x;
+            surfaceRefractionColor = texture2D(refraction2DSampler, refractionCoords, biasRefraction).rgb * vRefractionInfos.x;
         #endif    
         
         surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb); 
@@ -1125,15 +1146,34 @@ vec3 environmentIrradiance = vReflectionColor.rgb;
     vec3 vReflectionUVW = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
 
     #ifdef LODBASEDMICROSFURACE
-        float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+        #ifdef USEPMREMREFLECTION
+            float lodReflection = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.x, alphaG);
+        #else
+            float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+        #endif
+    #else
+        float biasReflection = (vMicrosurfaceTextureLods.x + 2.) * (1.0 - microSurface);
     #endif
     
     #ifdef REFLECTIONMAP_3D
         
         #ifdef LODBASEDMICROSFURACE
+            #ifdef USEPMREMREFLECTION
+                // Empiric Threshold
+                if (microSurface > 0.5)
+                {
+                    // Bend to not reach edges.
+                    float scaleReflection = 1. - exp2(lodReflection) / exp2(vMicrosurfaceTextureLods.x); // CubemapSize is the size of the base mipmap
+                    float maxReflection = max(max(abs(vReflectionUVW.x), abs(vReflectionUVW.y)), abs(vReflectionUVW.z));
+                    if (abs(vReflectionUVW.x) != maxReflection) vReflectionUVW.x *= scaleReflection;
+                    if (abs(vReflectionUVW.y) != maxReflection) vReflectionUVW.y *= scaleReflection;
+                    if (abs(vReflectionUVW.z) != maxReflection) vReflectionUVW.z *= scaleReflection;
+                }
+            #endif
+                
             environmentRadiance = textureCubeLodEXT(reflectionCubeSampler, vReflectionUVW, lodReflection).rgb * vReflectionInfos.x;
         #else
-            environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, bias).rgb * vReflectionInfos.x;
+            environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, biasReflection).rgb * vReflectionInfos.x;
         #endif
         
         #ifdef PoissonSamplingEnvironment
@@ -1163,7 +1203,7 @@ vec3 environmentIrradiance = vReflectionColor.rgb;
         #ifdef LODBASEDMICROSFURACE
             environmentRadiance = texture2DLodEXT(reflection2DSampler, coords, lodReflection).rgb * vReflectionInfos.x;
         #else
-            environmentRadiance = texture2D(reflection2DSampler, coords, bias).rgb * vReflectionInfos.x;
+            environmentRadiance = texture2D(reflection2DSampler, coords, biasReflection).rgb * vReflectionInfos.x;
         #endif
     
         environmentRadiance = toLinearSpace(environmentRadiance.rgb);

+ 9 - 8
materialsLibrary/materials/simple/simple.fragment.fx

@@ -16,10 +16,10 @@ varying vec4 vColor;
 #endif
 
 // Lights
-#include<light0FragmentDeclaration>
-#include<light1FragmentDeclaration>
-#include<light2FragmentDeclaration>
-#include<light3FragmentDeclaration>
+#include<lightFragmentDeclaration>[0]
+#include<lightFragmentDeclaration>[1]
+#include<lightFragmentDeclaration>[2]
+#include<lightFragmentDeclaration>[3]
 
 
 #include<lightsFragmentFunctions>
@@ -73,13 +73,14 @@ void main(void) {
 
 	// Lighting
 	vec3 diffuseBase = vec3(0., 0., 0.);
+    lightingInfo info;
 	float shadow = 1.;
     float glossiness = 0.;
     
-#include<light0Fragment>
-#include<light1Fragment>
-#include<light2Fragment>
-#include<light3Fragment>
+#include<lightFragment>[0]
+#include<lightFragment>[1]
+#include<lightFragment>[2]
+#include<lightFragment>[3]
 
 
 #ifdef VERTEXALPHA

+ 27 - 9
materialsLibrary/materials/sky/babylon.skyMaterial.ts

@@ -40,8 +40,14 @@ module BABYLON {
         @serialize()
         public azimuth: number = 0.25;
         
+        @serializeAsVector3()
+        public sunPosition: Vector3 = new Vector3(0, 100, 0);
+        
+        @serialize()
+        public useSunPosition: boolean = false;
+        
         // Private members
-        private _sunPosition: Vector3 = Vector3.Zero();
+        private _cameraPosition: Vector3 = Vector3.Zero();
         
         private _renderId: number;
         
@@ -150,7 +156,8 @@ module BABYLON {
                     attribs,
                     ["world", "viewProjection", "view",
                         "vFogInfos", "vFogColor", "pointSize", "vClipPlane",
-                        "luminance", "turbidity", "rayleigh", "mieCoefficient", "mieDirectionalG", "sunPosition"
+                        "luminance", "turbidity", "rayleigh", "mieCoefficient", "mieDirectionalG", "sunPosition",
+                        "cameraPosition"
                     ],
                     [],
                     join, fallbacks, this.onCompiled, this.onError);
@@ -207,20 +214,31 @@ module BABYLON {
             MaterialHelper.BindFogParameters(scene, mesh, this._effect);
             
             // Sky
+            var camera = scene.activeCamera;
+            if (camera) {
+                var cameraWorldMatrix = camera.getWorldMatrix();
+                this._cameraPosition.x = cameraWorldMatrix.m[12];
+                this._cameraPosition.y = cameraWorldMatrix.m[13];
+                this._cameraPosition.z = cameraWorldMatrix.m[14];
+                this._effect.setVector3("cameraPosition", this._cameraPosition);
+            }
+            
             this._effect.setFloat("luminance", this.luminance);
 			this._effect.setFloat("turbidity", this.turbidity);
 			this._effect.setFloat("rayleigh", this.rayleigh);
 			this._effect.setFloat("mieCoefficient", this.mieCoefficient);
 			this._effect.setFloat("mieDirectionalG", this.mieDirectionalG);
             
-            var theta = Math.PI * (this.inclination - 0.5);
-			var phi = 2 * Math.PI * (this.azimuth - 0.5);
-            
-            this._sunPosition.x = this.distance * Math.cos( phi );
-			this._sunPosition.y = this.distance * Math.sin( phi ) * Math.sin( theta );
-			this._sunPosition.z = this.distance * Math.sin( phi ) * Math.cos( theta );
+            if (!this.useSunPosition) {
+                var theta = Math.PI * (this.inclination - 0.5);
+                var phi = 2 * Math.PI * (this.azimuth - 0.5);
+                
+                this.sunPosition.x = this.distance * Math.cos(phi);
+                this.sunPosition.y = this.distance * Math.sin(phi) * Math.sin(theta);
+                this.sunPosition.z = this.distance * Math.sin(phi) * Math.cos(theta);
+            }
             
-			this._effect.setVector3("sunPosition", this._sunPosition);
+			this._effect.setVector3("sunPosition", this.sunPosition);
 
             super.bind(world, mesh);
         }

+ 4 - 4
materialsLibrary/materials/sky/sky.fragment.fx

@@ -10,6 +10,7 @@ varying vec4 vColor;
 #include<clipPlaneFragmentDeclaration>
 
 // Sky
+uniform vec3 cameraPosition;
 uniform float luminance;
 uniform float turbidity;
 uniform float rayleigh;
@@ -95,18 +96,17 @@ void main(void) {
 	* Sky Color
 	*--------------------------------------------------------------------------------------------------
 	*/
-	const vec3 cameraPos = vec3(0.0, 0.0, 0.0);
 	float sunfade = 1.0 - clamp(1.0 - exp((sunPosition.y / 450000.0)), 0.0, 1.0);
 	float rayleighCoefficient = rayleigh - (1.0 * (1.0 - sunfade));
 	vec3 sunDirection = normalize(sunPosition);
 	float sunE = sunIntensity(dot(sunDirection, up));
 	vec3 betaR = simplifiedRayleigh() * rayleighCoefficient;
 	vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;
-	float zenithAngle = acos(max(0.0, dot(up, normalize(vPositionW - cameraPos))));
+	float zenithAngle = acos(max(0.0, dot(up, normalize(vPositionW - cameraPosition))));
 	float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));
 	float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));
 	vec3 Fex = exp(-(betaR * sR + betaM * sM));
-	float cosTheta = dot(normalize(vPositionW - cameraPos), sunDirection);
+	float cosTheta = dot(normalize(vPositionW - cameraPosition), sunDirection);
 	float rPhase = rayleighPhase(cosTheta*0.5+0.5);
 	vec3 betaRTheta = betaR * rPhase;
 	float mPhase = hgPhase(cosTheta, mieDirectionalG);
@@ -115,7 +115,7 @@ void main(void) {
 	vec3 Lin = pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex),vec3(1.5));
 	Lin *= mix(vec3(1.0), pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex, vec3(1.0 / 2.0)), clamp(pow(1.0-dot(up, sunDirection), 5.0), 0.0, 1.0));
 
-	vec3 direction = normalize(vPositionW - cameraPos);
+	vec3 direction = normalize(vPositionW - cameraPosition);
 	float theta = acos(direction.y);
 	float phi = atan(direction.z, direction.x);
 	vec2 uv = vec2(phi, theta) / vec2(2.0 * pi, pi) + vec2(0.5, 0.0);

+ 3 - 0
materialsLibrary/test/add/addpbr.js

@@ -6,6 +6,9 @@ window.preparePBR = function() {
 	pbr.albedoTexture.vScale = 5;
     
     var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 512);
+    
+    // Uncomment for PMREM Generation
+    // var hdrTexture = new BABYLON.HDRCubeTexture("textures/hdr/environment.hdr", scene, 128, false, true, false, true);
     pbr.reflectionTexture = hdrTexture;
     pbr.refractionTexture = hdrTexture;
     pbr.linkRefractionWithTransparency = true;

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2683 - 1084
materialsLibrary/test/refs/babylon.max.js


+ 17 - 0
src/Animations/babylon.animatable.js

@@ -49,6 +49,19 @@ var BABYLON;
             this._localDelayOffset = null;
             this._pausedDelay = null;
         };
+        Animatable.prototype.enableBlending = function (blendingSpeed) {
+            var animations = this._animations;
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].enableBlending = true;
+                animations[index].blendingSpeed = blendingSpeed;
+            }
+        };
+        Animatable.prototype.disableBlending = function () {
+            var animations = this._animations;
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].enableBlending = false;
+            }
+        };
         Animatable.prototype.goToFrame = function (frame) {
             var animations = this._animations;
             for (var index = 0; index < animations.length; index++) {
@@ -68,6 +81,10 @@ var BABYLON;
             var index = this._scene._activeAnimatables.indexOf(this);
             if (index > -1) {
                 this._scene._activeAnimatables.splice(index, 1);
+                var animations = this._animations;
+                for (var index = 0; index < animations.length; index++) {
+                    animations[index].reset();
+                }
                 if (this.onAnimationEnd) {
                     this.onAnimationEnd();
                 }

+ 21 - 0
src/Animations/babylon.animatable.ts

@@ -52,7 +52,23 @@
 
             this._localDelayOffset = null;
             this._pausedDelay = null;
+        }
+
+        public enableBlending(blendingSpeed: number): void {
+            var animations = this._animations;
 
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].enableBlending = true;
+                animations[index].blendingSpeed = blendingSpeed;
+            }
+        }
+
+        public disableBlending(): void {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].enableBlending = false;
+            }
         }
 
         public goToFrame(frame: number): void {
@@ -80,6 +96,11 @@
             if (index > -1) {
                 this._scene._activeAnimatables.splice(index, 1);
 
+                var animations = this._animations;
+                for (var index = 0; index < animations.length; index++) {
+                    animations[index].reset();
+                }
+
                 if (this.onAnimationEnd) {
                     this.onAnimationEnd();
                 }

+ 94 - 5
src/Animations/babylon.animation.js

@@ -22,19 +22,79 @@ var BABYLON;
         return AnimationEvent;
     })();
     BABYLON.AnimationEvent = AnimationEvent;
+    var PathCursor = (function () {
+        function PathCursor(path) {
+            this.path = path;
+            this._onchange = new Array();
+            this.value = 0;
+            this.animations = new Array();
+        }
+        PathCursor.prototype.getPoint = function () {
+            var point = this.path.getPointAtLengthPosition(this.value);
+            return new BABYLON.Vector3(point.x, 0, point.y);
+        };
+        PathCursor.prototype.moveAhead = function (step) {
+            if (step === void 0) { step = 0.002; }
+            this.move(step);
+            return this;
+        };
+        PathCursor.prototype.moveBack = function (step) {
+            if (step === void 0) { step = 0.002; }
+            this.move(-step);
+            return this;
+        };
+        PathCursor.prototype.move = function (step) {
+            if (Math.abs(step) > 1) {
+                throw "step size should be less than 1.";
+            }
+            this.value += step;
+            this.ensureLimits();
+            this.raiseOnChange();
+            return this;
+        };
+        PathCursor.prototype.ensureLimits = function () {
+            while (this.value > 1) {
+                this.value -= 1;
+            }
+            while (this.value < 0) {
+                this.value += 1;
+            }
+            return this;
+        };
+        // used by animation engine
+        PathCursor.prototype.markAsDirty = function (propertyName) {
+            this.ensureLimits();
+            this.raiseOnChange();
+            return this;
+        };
+        PathCursor.prototype.raiseOnChange = function () {
+            var _this = this;
+            this._onchange.forEach(function (f) { return f(_this); });
+            return this;
+        };
+        PathCursor.prototype.onchange = function (f) {
+            this._onchange.push(f);
+            return this;
+        };
+        return PathCursor;
+    })();
+    BABYLON.PathCursor = PathCursor;
     var Animation = (function () {
-        function Animation(name, targetProperty, framePerSecond, dataType, loopMode) {
+        function Animation(name, targetProperty, framePerSecond, dataType, loopMode, enableBlending) {
             this.name = name;
             this.targetProperty = targetProperty;
             this.framePerSecond = framePerSecond;
             this.dataType = dataType;
             this.loopMode = loopMode;
+            this.enableBlending = enableBlending;
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
+            this._blendingFactor = 0;
             // The set of event that will be linked to this animation
             this._events = new Array();
             this.allowMatricesInterpolation = false;
+            this.blendingSpeed = 0.01;
             this._ranges = {};
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
@@ -127,6 +187,8 @@ var BABYLON;
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this.currentFrame = 0;
+            this._blendingFactor = 0;
+            this._originalBlendValue = null;
         };
         Animation.prototype.isStopped = function () {
             return this._stopped;
@@ -277,17 +339,43 @@ var BABYLON;
             }
             return this._getKeyValue(this._keys[this._keys.length - 1].value);
         };
-        Animation.prototype.setValue = function (currentValue) {
+        Animation.prototype.setValue = function (currentValue, blend) {
+            if (blend === void 0) { blend = false; }
             // Set value
+            var path;
+            var destination;
             if (this.targetPropertyPath.length > 1) {
                 var property = this._target[this.targetPropertyPath[0]];
                 for (var index = 1; index < this.targetPropertyPath.length - 1; index++) {
                     property = property[this.targetPropertyPath[index]];
                 }
-                property[this.targetPropertyPath[this.targetPropertyPath.length - 1]] = currentValue;
+                path = this.targetPropertyPath[this.targetPropertyPath.length - 1];
+                destination = property;
+            }
+            else {
+                path = this.targetPropertyPath[0];
+                destination = this._target;
+            }
+            // Blending
+            if (this.enableBlending && this._blendingFactor <= 1.0) {
+                if (!this._originalBlendValue) {
+                    this._originalBlendValue = destination[path];
+                }
+                if (this._originalBlendValue.prototype) {
+                    if (this._originalBlendValue.prototype.Lerp) {
+                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    }
+                    else {
+                        destination[path] = currentValue;
+                    }
+                }
+                else {
+                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                }
+                this._blendingFactor += this.blendingSpeed;
             }
             else {
-                this._target[this.targetPropertyPath[0]] = currentValue;
+                destination[path] = currentValue;
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this.targetProperty);
@@ -303,7 +391,8 @@ var BABYLON;
             var currentValue = this._interpolate(frame, 0, this.loopMode);
             this.setValue(currentValue);
         };
-        Animation.prototype.animate = function (delay, from, to, loop, speedRatio) {
+        Animation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
+            if (blend === void 0) { blend = false; }
             if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
                 this._stopped = true;
                 return false;

+ 109 - 6
src/Animations/babylon.animation.ts

@@ -13,12 +13,84 @@
         }
     }
 
+    export class PathCursor {
+        private _onchange = new Array<(cursor: PathCursor) => void>();
+
+        value: number = 0;
+        animations = new Array<Animation>();
+
+        constructor(private path: Path2) {
+        }
+
+        public getPoint(): Vector3 {
+            var point = this.path.getPointAtLengthPosition(this.value);
+            return new Vector3(point.x, 0, point.y);
+        }
+
+        public moveAhead(step: number = 0.002): PathCursor {
+            this.move(step);
+
+            return this;
+        }
+
+        public moveBack(step: number = 0.002): PathCursor {
+            this.move(-step);
+
+            return this;
+        }
+
+        public move(step: number): PathCursor {
+
+            if (Math.abs(step) > 1) {
+                throw "step size should be less than 1.";
+            }
+
+            this.value += step;
+            this.ensureLimits();
+            this.raiseOnChange();
+
+            return this;
+        }
+
+        private ensureLimits(): PathCursor {
+            while (this.value > 1) {
+                this.value -= 1;
+            }
+            while (this.value < 0) {
+                this.value += 1;
+            }
+
+            return this;
+        }
+
+        // used by animation engine
+        private markAsDirty(propertyName: string): PathCursor {
+            this.ensureLimits();
+            this.raiseOnChange();
+
+            return this;
+        }
+
+        private raiseOnChange(): PathCursor {
+            this._onchange.forEach(f => f(this));
+
+            return this;
+        }
+
+        public onchange(f: (cursor: PathCursor) => void): PathCursor {
+            this._onchange.push(f);
+
+            return this;
+        }
+    }
+
     export class Animation {
         private _keys: Array<any>;
         private _offsetsCache = {};
         private _highLimitsCache = {};
         private _stopped = false;
         public _target;
+        private _blendingFactor = 0;
         private _easingFunction: IEasingFunction;
 
         // The set of event that will be linked to this animation
@@ -29,6 +101,9 @@
 
         public allowMatricesInterpolation = false;
 
+        public blendingSpeed = 0.01;
+        private _originalBlendValue: any;
+
         private _ranges: { [name: string]: AnimationRange; } = {};
 
         static _PrepareAnimation(name: string, targetProperty: string, framePerSecond: number, totalFrame: number,
@@ -85,7 +160,7 @@
             return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
         }
 
-        constructor(public name: string, public targetProperty: string, public framePerSecond: number, public dataType: number, public loopMode?: number) {
+        constructor(public name: string, public targetProperty: string, public framePerSecond: number, public dataType: number, public loopMode?: number, public enableBlending?: boolean) {
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
             this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
@@ -144,6 +219,8 @@
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this.currentFrame = 0;
+            this._blendingFactor = 0;
+            this._originalBlendValue = null;
         }
 
         public isStopped(): boolean {
@@ -323,8 +400,11 @@
             return this._getKeyValue(this._keys[this._keys.length - 1].value);
         }
 
-        public setValue(currentValue: any): void {
+        public setValue(currentValue: any, blend: boolean = false): void {
             // Set value
+            var path: any;
+            var destination: any;
+
             if (this.targetPropertyPath.length > 1) {
                 var property = this._target[this.targetPropertyPath[0]];
 
@@ -332,9 +412,33 @@
                     property = property[this.targetPropertyPath[index]];
                 }
 
-                property[this.targetPropertyPath[this.targetPropertyPath.length - 1]] = currentValue;
+                path = this.targetPropertyPath[this.targetPropertyPath.length - 1]
+                destination = property;
             } else {
-                this._target[this.targetPropertyPath[0]] = currentValue;
+                path = this.targetPropertyPath[0];
+                destination = this._target;
+            }
+
+            // Blending
+            if (this.enableBlending && this._blendingFactor <= 1.0) {
+                if (!this._originalBlendValue) {
+                    this._originalBlendValue = destination[path];
+                }
+
+                if (this._originalBlendValue.prototype) { // Complex value
+                    
+                    if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
+                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    } else { // Blending not supported
+                        destination[path] = currentValue;
+                    }
+
+                } else { // Direct value
+                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                }
+                this._blendingFactor += this.blendingSpeed;
+            } else {
+                destination[path] = currentValue;
             }
 
             if (this._target.markAsDirty) {
@@ -354,7 +458,7 @@
             this.setValue(currentValue);
         }
 
-        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number): boolean {
+        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, blend: boolean = false): boolean {
             if (!this.targetPropertyPath || this.targetPropertyPath.length < 1) {
                 this._stopped = true;
                 return false;
@@ -633,4 +737,3 @@
 } 
 
 
-

+ 1 - 0
src/Bones/babylon.bone.js

@@ -85,6 +85,7 @@ var BABYLON;
             // all animation may be coming from a library skeleton, so may need to create animation
             if (this.animations.length === 0) {
                 this.animations.push(new BABYLON.Animation(this.name, "_matrix", source.animations[0].framePerSecond, BABYLON.Animation.ANIMATIONTYPE_MATRIX, 0));
+                this.animations[0].setKeys([{}]);
             }
             // get animation info / verify there is such a range from the source bone
             var sourceRange = source.animations[0].getRange(rangeName);

+ 1 - 0
src/Bones/babylon.bone.ts

@@ -102,6 +102,7 @@
             // all animation may be coming from a library skeleton, so may need to create animation
             if (this.animations.length === 0) {
                 this.animations.push(new Animation(this.name, "_matrix", source.animations[0].framePerSecond, Animation.ANIMATIONTYPE_MATRIX, 0));
+                this.animations[0].setKeys([{}]);
             }
 
             // get animation info / verify there is such a range from the source bone

+ 2 - 2
src/Cameras/VR/babylon.webVRCamera.js

@@ -48,9 +48,9 @@ var BABYLON;
                 this._cacheState = this._sensorDevice.getState();
                 this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
                 this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
-                this.rotation.x = -this._cacheRotation.z;
+                this.rotation.x = -this._cacheRotation.x;
                 this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.x;
+                this.rotation.z = this._cacheRotation.z;
             }
             _super.prototype._checkInputs.call(this);
         };

+ 5 - 4
src/Cameras/VR/babylon.webVRCamera.ts

@@ -12,7 +12,7 @@ module BABYLON {
 
         constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
             super(name, position, scene);
-            
+
             var metrics = VRCameraMetrics.GetDefault();
             metrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
@@ -54,9 +54,9 @@ module BABYLON {
                 this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
                 this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
 
-                this.rotation.x = -this._cacheRotation.z;
+                this.rotation.x = -this._cacheRotation.x;
                 this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.x;
+                this.rotation.z = this._cacheRotation.z;
             }
 
             super._checkInputs();
@@ -82,4 +82,5 @@ module BABYLON {
             return "WebVRFreeCamera";
         }
     }
-}
+}
+

+ 5 - 5
src/Cameras/babylon.arcRotateCamera.js

@@ -399,11 +399,11 @@ var BABYLON;
                 this.inertialAlphaOffset *= this.inertia;
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
-                if (Math.abs(this.inertialAlphaOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialAlphaOffset) < BABYLON.Epsilon)
                     this.inertialAlphaOffset = 0;
-                if (Math.abs(this.inertialBetaOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialBetaOffset) < BABYLON.Epsilon)
                     this.inertialBetaOffset = 0;
-                if (Math.abs(this.inertialRadiusOffset) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialRadiusOffset) < BABYLON.Epsilon)
                     this.inertialRadiusOffset = 0;
             }
             // Panning inertia
@@ -414,9 +414,9 @@ var BABYLON;
                 }
                 this.inertialPanningX *= this.inertia;
                 this.inertialPanningY *= this.inertia;
-                if (Math.abs(this.inertialPanningX) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialPanningX) < BABYLON.Epsilon)
                     this.inertialPanningX = 0;
-                if (Math.abs(this.inertialPanningY) < BABYLON.Engine.Epsilon)
+                if (Math.abs(this.inertialPanningY) < BABYLON.Epsilon)
                     this.inertialPanningY = 0;
                 this._localDirection.copyFromFloats(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
                 this._localDirection.multiplyInPlace(this.panningAxis);

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

@@ -482,11 +482,11 @@
                 this.inertialAlphaOffset *= this.inertia;
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
-                if (Math.abs(this.inertialAlphaOffset) < Engine.Epsilon)
+                if (Math.abs(this.inertialAlphaOffset) < Epsilon)
                     this.inertialAlphaOffset = 0;
-                if (Math.abs(this.inertialBetaOffset) < Engine.Epsilon)
+                if (Math.abs(this.inertialBetaOffset) < Epsilon)
                     this.inertialBetaOffset = 0;
-                if (Math.abs(this.inertialRadiusOffset) < Engine.Epsilon)
+                if (Math.abs(this.inertialRadiusOffset) < Epsilon)
                     this.inertialRadiusOffset = 0;
             }
 
@@ -500,9 +500,9 @@
                 this.inertialPanningX *= this.inertia;
                 this.inertialPanningY *= this.inertia;
 
-                if (Math.abs(this.inertialPanningX) < Engine.Epsilon)
+                if (Math.abs(this.inertialPanningX) < Epsilon)
                     this.inertialPanningX = 0;
-                if (Math.abs(this.inertialPanningY) < Engine.Epsilon)
+                if (Math.abs(this.inertialPanningY) < Epsilon)
                     this.inertialPanningY = 0;
 
                 this._localDirection.copyFromFloats(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
@@ -745,4 +745,3 @@
         }
     }
 } 
-

+ 2 - 2
src/Cameras/babylon.camera.js

@@ -333,7 +333,7 @@ var BABYLON;
                 if (this.minZ <= 0) {
                     this.minZ = 0.1;
                 }
-                BABYLON.Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix, this.fovMode);
+                BABYLON.Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix, this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
                 return this._projectionMatrix;
             }
             var halfWidth = engine.getRenderWidth() / 2.0;
@@ -543,7 +543,7 @@ var BABYLON;
                 BABYLON.Node.ParseAnimationRanges(camera, parsedCamera, scene);
             }
             if (parsedCamera.autoAnimate) {
-                scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, 1.0);
+                scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, parsedCamera.autoAnimateSpeed || 1.0);
             }
             return camera;
         };

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

@@ -411,7 +411,7 @@
                     this.minZ = 0.1;
                 }
 
-                Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix, this.fovMode);
+                Matrix.PerspectiveFovLHToRef(this.fov, engine.getAspectRatio(this), this.minZ, this.maxZ, this._projectionMatrix, this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
                 return this._projectionMatrix;
             }
 
@@ -660,7 +660,7 @@
             }
 
             if (parsedCamera.autoAnimate) {
-                scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, 1.0);
+                scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, parsedCamera.autoAnimateSpeed || 1.0);
             }
 
             return camera;

+ 5 - 5
src/Cameras/babylon.targetCamera.js

@@ -135,22 +135,22 @@ var BABYLON;
             }
             // Inertia
             if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.x) < BABYLON.Epsilon) {
                     this.cameraDirection.x = 0;
                 }
-                if (Math.abs(this.cameraDirection.y) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.y) < BABYLON.Epsilon) {
                     this.cameraDirection.y = 0;
                 }
-                if (Math.abs(this.cameraDirection.z) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.z) < BABYLON.Epsilon) {
                     this.cameraDirection.z = 0;
                 }
                 this.cameraDirection.scaleInPlace(this.inertia);
             }
             if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.x) < BABYLON.Epsilon) {
                     this.cameraRotation.x = 0;
                 }
-                if (Math.abs(this.cameraRotation.y) < BABYLON.Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.y) < BABYLON.Epsilon) {
                     this.cameraRotation.y = 0;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);

+ 7 - 7
src/Cameras/babylon.targetCamera.ts

@@ -166,26 +166,26 @@
 
             // Inertia
             if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.x) < Epsilon) {
                     this.cameraDirection.x = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.y) < Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.y) < Epsilon) {
                     this.cameraDirection.y = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.z) < Engine.Epsilon) {
+                if (Math.abs(this.cameraDirection.z) < Epsilon) {
                     this.cameraDirection.z = 0;
                 }
 
                 this.cameraDirection.scaleInPlace(this.inertia);
             }
             if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.x) < Epsilon) {
                     this.cameraRotation.x = 0;
                 }
 
-                if (Math.abs(this.cameraRotation.y) < Engine.Epsilon) {
+                if (Math.abs(this.cameraRotation.y) < Epsilon) {
                     this.cameraRotation.y = 0;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);
@@ -265,8 +265,8 @@
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_VR:
-                    var camLeft = <TargetCamera> this._rigCameras[0];
-                    var camRight = <TargetCamera> this._rigCameras[1];
+                    var camLeft = <TargetCamera>this._rigCameras[0];
+                    var camRight = <TargetCamera>this._rigCameras[1];
 
                     if (this.cameraRigMode === Camera.RIG_MODE_VR) {
                         camLeft.rotation.x = camRight.rotation.x = this.rotation.x;

+ 1 - 1
src/Culling/babylon.boundingBox.js

@@ -75,7 +75,7 @@ var BABYLON;
             return BoundingBox.IsCompletelyInFrustum(this.vectorsWorld, frustumPlanes);
         };
         BoundingBox.prototype.intersectsPoint = function (point) {
-            var delta = -BABYLON.Engine.Epsilon;
+            var delta = -BABYLON.Epsilon;
             if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
                 return false;
             if (this.maximumWorld.y - point.y < delta || delta > point.y - this.minimumWorld.y)

+ 1 - 1
src/Culling/babylon.boundingBox.ts

@@ -101,7 +101,7 @@
         }
 
         public intersectsPoint(point: Vector3): boolean {
-            var delta = -Engine.Epsilon;
+            var delta = -Epsilon;
 
             if (this.maximumWorld.x - point.x < delta || delta > point.x - this.minimumWorld.x)
                 return false;

+ 1 - 1
src/Culling/babylon.boundingSphere.js

@@ -29,7 +29,7 @@ var BABYLON;
             var y = this.centerWorld.y - point.y;
             var z = this.centerWorld.z - point.z;
             var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (Math.abs(this.radiusWorld - distance) < BABYLON.Engine.Epsilon)
+            if (Math.abs(this.radiusWorld - distance) < BABYLON.Epsilon)
                 return false;
             return true;
         };

+ 1 - 1
src/Culling/babylon.boundingSphere.ts

@@ -40,7 +40,7 @@
 
             var distance = Math.sqrt((x * x) + (y * y) + (z * z));
 
-            if (Math.abs(this.radiusWorld - distance) < Engine.Epsilon)
+            if (Math.abs(this.radiusWorld - distance) < Epsilon)
                 return false;
 
             return true;

+ 171 - 0
src/Culling/babylon.ray.js

@@ -0,0 +1,171 @@
+var BABYLON;
+(function (BABYLON) {
+    var Ray = (function () {
+        function Ray(origin, direction, length) {
+            if (length === void 0) { length = Number.MAX_VALUE; }
+            this.origin = origin;
+            this.direction = direction;
+            this.length = length;
+        }
+        // Methods
+        Ray.prototype.intersectsBoxMinMax = function (minimum, maximum) {
+            var d = 0.0;
+            var maxValue = Number.MAX_VALUE;
+            var inv;
+            var min;
+            var max;
+            var temp;
+            if (Math.abs(this.direction.x) < 0.0000001) {
+                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.x;
+                min = (minimum.x - this.origin.x) * inv;
+                max = (maximum.x - this.origin.x) * inv;
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+            if (Math.abs(this.direction.y) < 0.0000001) {
+                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.y;
+                min = (minimum.y - this.origin.y) * inv;
+                max = (maximum.y - this.origin.y) * inv;
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+            if (Math.abs(this.direction.z) < 0.0000001) {
+                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.z;
+                min = (minimum.z - this.origin.z) * inv;
+                max = (maximum.z - this.origin.z) * inv;
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+            return true;
+        };
+        Ray.prototype.intersectsBox = function (box) {
+            return this.intersectsBoxMinMax(box.minimum, box.maximum);
+        };
+        Ray.prototype.intersectsSphere = function (sphere) {
+            var x = sphere.center.x - this.origin.x;
+            var y = sphere.center.y - this.origin.y;
+            var z = sphere.center.z - this.origin.z;
+            var pyth = (x * x) + (y * y) + (z * z);
+            var rr = sphere.radius * sphere.radius;
+            if (pyth <= rr) {
+                return true;
+            }
+            var dot = (x * this.direction.x) + (y * this.direction.y) + (z * this.direction.z);
+            if (dot < 0.0) {
+                return false;
+            }
+            var temp = pyth - (dot * dot);
+            return temp <= rr;
+        };
+        Ray.prototype.intersectsTriangle = function (vertex0, vertex1, vertex2) {
+            if (!this._edge1) {
+                this._edge1 = BABYLON.Vector3.Zero();
+                this._edge2 = BABYLON.Vector3.Zero();
+                this._pvec = BABYLON.Vector3.Zero();
+                this._tvec = BABYLON.Vector3.Zero();
+                this._qvec = BABYLON.Vector3.Zero();
+            }
+            vertex1.subtractToRef(vertex0, this._edge1);
+            vertex2.subtractToRef(vertex0, this._edge2);
+            BABYLON.Vector3.CrossToRef(this.direction, this._edge2, this._pvec);
+            var det = BABYLON.Vector3.Dot(this._edge1, this._pvec);
+            if (det === 0) {
+                return null;
+            }
+            var invdet = 1 / det;
+            this.origin.subtractToRef(vertex0, this._tvec);
+            var bu = BABYLON.Vector3.Dot(this._tvec, this._pvec) * invdet;
+            if (bu < 0 || bu > 1.0) {
+                return null;
+            }
+            BABYLON.Vector3.CrossToRef(this._tvec, this._edge1, this._qvec);
+            var bv = BABYLON.Vector3.Dot(this.direction, this._qvec) * invdet;
+            if (bv < 0 || bu + bv > 1.0) {
+                return null;
+            }
+            //check if the distance is longer than the predefined length.
+            var distance = BABYLON.Vector3.Dot(this._edge2, this._qvec) * invdet;
+            if (distance > this.length) {
+                return null;
+            }
+            return new BABYLON.IntersectionInfo(bu, bv, distance);
+        };
+        // Statics
+        Ray.CreateNew = function (x, y, viewportWidth, viewportHeight, world, view, projection) {
+            var start = BABYLON.Vector3.Unproject(new BABYLON.Vector3(x, y, 0), viewportWidth, viewportHeight, world, view, projection);
+            var end = BABYLON.Vector3.Unproject(new BABYLON.Vector3(x, y, 1), viewportWidth, viewportHeight, world, view, projection);
+            var direction = end.subtract(start);
+            direction.normalize();
+            return new Ray(start, direction);
+        };
+        /**
+        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
+        * transformed to the given world matrix.
+        * @param origin The origin point
+        * @param end The end point
+        * @param world a matrix to transform the ray to. Default is the identity matrix.
+        */
+        Ray.CreateNewFromTo = function (origin, end, world) {
+            if (world === void 0) { world = BABYLON.Matrix.Identity(); }
+            var direction = end.subtract(origin);
+            var length = Math.sqrt((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z));
+            direction.normalize();
+            return Ray.Transform(new Ray(origin, direction, length), world);
+        };
+        Ray.Transform = function (ray, matrix) {
+            var newOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, matrix);
+            var newDirection = BABYLON.Vector3.TransformNormal(ray.direction, matrix);
+            return new Ray(newOrigin, newDirection, ray.length);
+        };
+        return Ray;
+    })();
+    BABYLON.Ray = Ray;
+})(BABYLON || (BABYLON = {}));

+ 208 - 0
src/Culling/babylon.ray.ts

@@ -0,0 +1,208 @@
+module BABYLON {
+    export class Ray {
+        private _edge1: Vector3;
+        private _edge2: Vector3;
+        private _pvec: Vector3;
+        private _tvec: Vector3;
+        private _qvec: Vector3;
+
+        constructor(public origin: Vector3, public direction: Vector3, public length: number = Number.MAX_VALUE) {
+        }
+
+        // Methods
+        public intersectsBoxMinMax(minimum: Vector3, maximum: Vector3): boolean {
+            var d = 0.0;
+            var maxValue = Number.MAX_VALUE;
+            var inv: number;
+            var min: number;
+            var max: number;
+            var temp: number;
+            if (Math.abs(this.direction.x) < 0.0000001) {
+                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.x;
+                min = (minimum.x - this.origin.x) * inv;
+                max = (maximum.x - this.origin.x) * inv;
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+
+            if (Math.abs(this.direction.y) < 0.0000001) {
+                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.y;
+                min = (minimum.y - this.origin.y) * inv;
+                max = (maximum.y - this.origin.y) * inv;
+
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+
+            if (Math.abs(this.direction.z) < 0.0000001) {
+                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
+                    return false;
+                }
+            }
+            else {
+                inv = 1.0 / this.direction.z;
+                min = (minimum.z - this.origin.z) * inv;
+                max = (maximum.z - this.origin.z) * inv;
+
+                if (max === -Infinity) {
+                    max = Infinity;
+                }
+
+                if (min > max) {
+                    temp = min;
+                    min = max;
+                    max = temp;
+                }
+
+                d = Math.max(min, d);
+                maxValue = Math.min(max, maxValue);
+
+                if (d > maxValue) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public intersectsBox(box: BoundingBox): boolean {
+            return this.intersectsBoxMinMax(box.minimum, box.maximum);
+        }
+
+        public intersectsSphere(sphere): boolean {
+            var x = sphere.center.x - this.origin.x;
+            var y = sphere.center.y - this.origin.y;
+            var z = sphere.center.z - this.origin.z;
+            var pyth = (x * x) + (y * y) + (z * z);
+            var rr = sphere.radius * sphere.radius;
+
+            if (pyth <= rr) {
+                return true;
+            }
+
+            var dot = (x * this.direction.x) + (y * this.direction.y) + (z * this.direction.z);
+            if (dot < 0.0) {
+                return false;
+            }
+
+            var temp = pyth - (dot * dot);
+
+            return temp <= rr;
+        }
+
+        public intersectsTriangle(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3): IntersectionInfo {
+            if (!this._edge1) {
+                this._edge1 = Vector3.Zero();
+                this._edge2 = Vector3.Zero();
+                this._pvec = Vector3.Zero();
+                this._tvec = Vector3.Zero();
+                this._qvec = Vector3.Zero();
+            }
+
+            vertex1.subtractToRef(vertex0, this._edge1);
+            vertex2.subtractToRef(vertex0, this._edge2);
+            Vector3.CrossToRef(this.direction, this._edge2, this._pvec);
+            var det = Vector3.Dot(this._edge1, this._pvec);
+
+            if (det === 0) {
+                return null;
+            }
+
+            var invdet = 1 / det;
+
+            this.origin.subtractToRef(vertex0, this._tvec);
+
+            var bu = Vector3.Dot(this._tvec, this._pvec) * invdet;
+
+            if (bu < 0 || bu > 1.0) {
+                return null;
+            }
+
+            Vector3.CrossToRef(this._tvec, this._edge1, this._qvec);
+
+            var bv = Vector3.Dot(this.direction, this._qvec) * invdet;
+
+            if (bv < 0 || bu + bv > 1.0) {
+                return null;
+            }
+
+            //check if the distance is longer than the predefined length.
+            var distance = Vector3.Dot(this._edge2, this._qvec) * invdet;
+            if (distance > this.length) {
+                return null;
+            }
+
+            return new IntersectionInfo(bu, bv, distance);
+        }
+
+        // Statics
+        public static CreateNew(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray {
+            var start = Vector3.Unproject(new Vector3(x, y, 0), viewportWidth, viewportHeight, world, view, projection);
+            var end = Vector3.Unproject(new Vector3(x, y, 1), viewportWidth, viewportHeight, world, view, projection);
+
+            var direction = end.subtract(start);
+            direction.normalize();
+
+            return new Ray(start, direction);
+        }
+
+        /**
+        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
+        * transformed to the given world matrix.
+        * @param origin The origin point
+        * @param end The end point
+        * @param world a matrix to transform the ray to. Default is the identity matrix.
+        */
+        public static CreateNewFromTo(origin: Vector3, end: Vector3, world: Matrix = Matrix.Identity()): Ray {
+            var direction = end.subtract(origin);
+            var length = Math.sqrt((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z));
+            direction.normalize();
+
+            return Ray.Transform(new Ray(origin, direction, length), world);
+        }
+
+        public static Transform(ray: Ray, matrix: Matrix): Ray {
+            var newOrigin = Vector3.TransformCoordinates(ray.origin, matrix);
+            var newDirection = Vector3.TransformNormal(ray.direction, matrix);
+
+            return new Ray(newOrigin, newDirection, ray.length);
+        }
+    }
+}

+ 35 - 1
src/Debug/babylon.debugLayer.js

@@ -9,6 +9,7 @@ var BABYLON;
             this._displayStatistics = true;
             this._displayTree = false;
             this._displayLogs = false;
+            this._skeletonViewers = new Array();
             this._identityMatrix = BABYLON.Matrix.Identity();
             this.axisRatio = 0.02;
             this.accentColor = "orange";
@@ -93,7 +94,7 @@ var BABYLON;
                     _this._drawingContext.clearRect(0, 0, _this._drawingCanvas.width, _this._drawingCanvas.height);
                     var engine = _this._scene.getEngine();
                     var viewport = _this._camera.viewport;
-                    var globalViewport = viewport.toGlobal(engine);
+                    var globalViewport = viewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
                     // Meshes
                     var meshes = _this._camera.getActiveMeshes();
                     var index;
@@ -262,6 +263,13 @@ var BABYLON;
             this._scene.renderTargetsEnabled = true;
             this._scene.probesEnabled = true;
             engine.getRenderingCanvas().removeEventListener("click", this._onCanvasClick);
+            this._clearSkeletonViewers();
+        };
+        DebugLayer.prototype._clearSkeletonViewers = function () {
+            for (var index = 0; index < this._skeletonViewers.length; index++) {
+                this._skeletonViewers[index].dispose();
+            }
+            this._skeletonViewers = [];
         };
         DebugLayer.prototype.show = function (showUI, camera, rootElement) {
             if (showUI === void 0) { showUI = true; }
@@ -556,6 +564,32 @@ var BABYLON;
                     });
                 }
                 this._optionsSubsetDiv.appendChild(document.createElement("br"));
+                this._generateTexBox(this._optionsSubsetDiv, "<b>Viewers:</b>", this.accentColor);
+                this._generateCheckBox(this._optionsSubsetDiv, "Skeletons", false, function (element) {
+                    if (!element.checked) {
+                        _this._clearSkeletonViewers();
+                        return;
+                    }
+                    for (var index = 0; index < _this._scene.meshes.length; index++) {
+                        var mesh = _this._scene.meshes[index];
+                        if (mesh.skeleton) {
+                            var found = false;
+                            for (var sIndex = 0; sIndex < _this._skeletonViewers.length; sIndex++) {
+                                if (_this._skeletonViewers[sIndex].skeleton === mesh.skeleton) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+                            if (found) {
+                                continue;
+                            }
+                            var viewer = new BABYLON.Debug.SkeletonViewer(mesh.skeleton, mesh, _this._scene);
+                            viewer.isEnabled = true;
+                            _this._skeletonViewers.push(viewer);
+                        }
+                    }
+                });
+                this._optionsSubsetDiv.appendChild(document.createElement("br"));
                 this._generateTexBox(this._optionsSubsetDiv, "<b>Tools:</b>", this.accentColor);
                 this._generateButton(this._optionsSubsetDiv, "Dump rendertargets", function (element) { _this._scene.dumpNextRenderTargets = true; });
                 this._generateButton(this._optionsSubsetDiv, "Run SceneOptimizer", function (element) { BABYLON.SceneOptimizer.OptimizeAsync(_this._scene); });

+ 44 - 1
src/Debug/babylon.debugLayer.ts

@@ -21,6 +21,8 @@
         private _drawingContext: CanvasRenderingContext2D;
         private _rootElement: HTMLElement;
 
+        private _skeletonViewers = new Array<Debug.SkeletonViewer>();
+
         public _syncPositions: () => void;
         private _syncData: () => void;
         private _syncUI: () => void;
@@ -143,7 +145,7 @@
 
                     var engine = this._scene.getEngine();
                     var viewport = this._camera.viewport;
-                    var globalViewport = viewport.toGlobal(engine);
+                    var globalViewport = viewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
 
                     // Meshes
                     var meshes = this._camera.getActiveMeshes();
@@ -368,6 +370,16 @@
             this._scene.probesEnabled = true;
 
             engine.getRenderingCanvas().removeEventListener("click", this._onCanvasClick);
+
+            this._clearSkeletonViewers();
+        }
+
+        private _clearSkeletonViewers(): void {
+            for (var index = 0; index < this._skeletonViewers.length; index++) {
+                this._skeletonViewers[index].dispose();
+            }
+
+            this._skeletonViewers = [];
         }
 
         public show(showUI: boolean = true, camera: Camera = null, rootElement: HTMLElement = null) {
@@ -699,6 +711,37 @@
                     });
                 }
                 this._optionsSubsetDiv.appendChild(document.createElement("br"));
+                this._generateTexBox(this._optionsSubsetDiv, "<b>Viewers:</b>", this.accentColor);
+                this._generateCheckBox(this._optionsSubsetDiv, "Skeletons", false, (element) => {
+
+                    if (!element.checked) {
+                        this._clearSkeletonViewers();
+                        return;
+                    }
+
+                    for (var index = 0; index < this._scene.meshes.length; index++) {
+                        var mesh = this._scene.meshes[index];
+
+                        if (mesh.skeleton) {
+                            var found = false;
+                            for (var sIndex = 0; sIndex < this._skeletonViewers.length; sIndex++) {
+                                if (this._skeletonViewers[sIndex].skeleton === mesh.skeleton) {
+                                    found = true;
+                                    break;
+                                }
+                            }
+
+                            if (found) {
+                                continue;
+                            }
+
+                            var viewer = new BABYLON.Debug.SkeletonViewer(mesh.skeleton, mesh, this._scene);
+                            viewer.isEnabled = true;
+                            this._skeletonViewers.push(viewer);
+                        }
+                    }
+                });
+                this._optionsSubsetDiv.appendChild(document.createElement("br"));
                 this._generateTexBox(this._optionsSubsetDiv, "<b>Tools:</b>", this.accentColor);
                 this._generateButton(this._optionsSubsetDiv, "Dump rendertargets", (element) => { this._scene.dumpNextRenderTargets = true; });
                 this._generateButton(this._optionsSubsetDiv, "Run SceneOptimizer", (element) => { SceneOptimizer.OptimizeAsync(this._scene); });

+ 137 - 0
src/Debug/babylon.skeletonViewer.js

@@ -0,0 +1,137 @@
+var BABYLON;
+(function (BABYLON) {
+    var Debug;
+    (function (Debug) {
+        /**
+        * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+        */
+        var SkeletonViewer = (function () {
+            function SkeletonViewer(skeleton, mesh, scene, autoUpdateBonesMatrices, renderingGroupId) {
+                if (autoUpdateBonesMatrices === void 0) { autoUpdateBonesMatrices = true; }
+                if (renderingGroupId === void 0) { renderingGroupId = 1; }
+                this.skeleton = skeleton;
+                this.mesh = mesh;
+                this.autoUpdateBonesMatrices = autoUpdateBonesMatrices;
+                this.renderingGroupId = renderingGroupId;
+                this.color = BABYLON.Color3.White();
+                this._debugLines = [];
+                this._isEnabled = false;
+                this._scene = scene;
+                this.update();
+                this._renderFunction = this.update.bind(this);
+            }
+            Object.defineProperty(SkeletonViewer.prototype, "isEnabled", {
+                get: function () {
+                    return this._isEnabled;
+                },
+                set: function (value) {
+                    if (this._isEnabled === value) {
+                        return;
+                    }
+                    this._isEnabled = value;
+                    if (value) {
+                        this._scene.registerBeforeRender(this._renderFunction);
+                    }
+                    else {
+                        this._scene.unregisterBeforeRender(this._renderFunction);
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            SkeletonViewer.prototype._getBonePosition = function (position, bone, meshMat, x, y, z) {
+                if (x === void 0) { x = 0; }
+                if (y === void 0) { y = 0; }
+                if (z === void 0) { z = 0; }
+                var tmat = BABYLON.Tmp.Matrix[0];
+                var parentBone = bone.getParent();
+                tmat.copyFrom(bone.getLocalMatrix());
+                if (x !== 0 || y !== 0 || z !== 0) {
+                    var tmat2 = BABYLON.Tmp.Matrix[1];
+                    BABYLON.Matrix.IdentityToRef(tmat2);
+                    tmat2.m[12] = x;
+                    tmat2.m[13] = y;
+                    tmat2.m[14] = z;
+                    tmat2.multiplyToRef(tmat, tmat);
+                }
+                if (parentBone) {
+                    tmat.multiplyToRef(parentBone.getAbsoluteTransform(), tmat);
+                }
+                tmat.multiplyToRef(meshMat, tmat);
+                position.x = tmat.m[12];
+                position.y = tmat.m[13];
+                position.z = tmat.m[14];
+            };
+            SkeletonViewer.prototype._getLinesForBonesWithLength = function (bones, meshMat) {
+                var len = bones.length;
+                for (var i = 0; i < len; i++) {
+                    var bone = bones[i];
+                    var points = this._debugLines[i];
+                    if (!points) {
+                        points = [BABYLON.Vector3.Zero(), BABYLON.Vector3.Zero()];
+                        this._debugLines[i] = points;
+                    }
+                    this._getBonePosition(points[0], bone, meshMat);
+                    this._getBonePosition(points[1], bone, meshMat, 0, bone.length, 0);
+                }
+            };
+            SkeletonViewer.prototype._getLinesForBonesNoLength = function (bones, meshMat) {
+                var len = bones.length;
+                var boneNum = 0;
+                for (var i = len - 1; i >= 0; i--) {
+                    var childBone = bones[i];
+                    var parentBone = childBone.getParent();
+                    if (!parentBone) {
+                        continue;
+                    }
+                    var points = this._debugLines[boneNum];
+                    if (!points) {
+                        points = [BABYLON.Vector3.Zero(), BABYLON.Vector3.Zero()];
+                        this._debugLines[boneNum] = points;
+                    }
+                    this._getBonePosition(points[0], childBone, meshMat);
+                    this._getBonePosition(points[1], parentBone, meshMat);
+                    boneNum++;
+                }
+            };
+            SkeletonViewer.prototype.update = function () {
+                if (this.autoUpdateBonesMatrices) {
+                    this._updateBoneMatrix(this.skeleton.bones[0]);
+                }
+                if (this.skeleton.bones[0].length === undefined) {
+                    this._getLinesForBonesNoLength(this.skeleton.bones, this.mesh.getWorldMatrix());
+                }
+                else {
+                    this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
+                }
+                if (!this._debugMesh) {
+                    this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem(null, { lines: this._debugLines, updatable: true }, this._scene);
+                    this._debugMesh.renderingGroupId = this.renderingGroupId;
+                }
+                else {
+                    BABYLON.MeshBuilder.CreateLineSystem(null, { lines: this._debugLines, updatable: true, instance: this._debugMesh }, this._scene);
+                }
+                this._debugMesh.color = this.color;
+            };
+            SkeletonViewer.prototype._updateBoneMatrix = function (bone) {
+                if (bone.getParent()) {
+                    bone.getLocalMatrix().multiplyToRef(bone.getParent().getAbsoluteTransform(), bone.getAbsoluteTransform());
+                }
+                var children = bone.children;
+                var len = children.length;
+                for (var i = 0; i < len; i++) {
+                    this._updateBoneMatrix(children[i]);
+                }
+            };
+            SkeletonViewer.prototype.dispose = function () {
+                if (this._debugMesh) {
+                    this.isEnabled = false;
+                    this._debugMesh.dispose();
+                    this._debugMesh = null;
+                }
+            };
+            return SkeletonViewer;
+        })();
+        Debug.SkeletonViewer = SkeletonViewer;
+    })(Debug = BABYLON.Debug || (BABYLON.Debug = {}));
+})(BABYLON || (BABYLON = {}));

+ 140 - 0
src/Debug/babylon.skeletonViewer.ts

@@ -0,0 +1,140 @@
+module BABYLON.Debug {
+    /**
+    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+    */
+    export class SkeletonViewer {
+        public color: Color3 = Color3.White();
+
+        private _scene: Scene;
+        private _debugLines = []; 
+        private _debugMesh: LinesMesh;
+        private _isEnabled = false;
+        private _renderFunction: () => void;
+
+        constructor(public skeleton: Skeleton, public mesh: AbstractMesh, scene: Scene, public autoUpdateBonesMatrices = true, public renderingGroupId = 1) {
+            this._scene = scene;
+
+            this.update();
+
+            this._renderFunction = this.update.bind(this);
+        }
+
+        public set isEnabled(value: boolean) {
+            if (this._isEnabled === value) {
+                return;
+            }
+
+            this._isEnabled = value;
+
+            if (value) {
+                this._scene.registerBeforeRender(this._renderFunction);
+            } else {
+                this._scene.unregisterBeforeRender(this._renderFunction);
+            }
+        }
+
+        public get isEnabled(): boolean {
+            return this._isEnabled;
+        }
+
+        private _getBonePosition(position: Vector3, bone: Bone, meshMat: Matrix, x = 0, y = 0, z = 0): void {
+            var tmat = Tmp.Matrix[0];
+            var parentBone = bone.getParent();
+            tmat.copyFrom(bone.getLocalMatrix());
+
+            if (x !== 0 || y !== 0 || z !== 0) {
+                var tmat2 = Tmp.Matrix[1];
+                BABYLON.Matrix.IdentityToRef(tmat2);
+                tmat2.m[12] = x;
+                tmat2.m[13] = y;
+                tmat2.m[14] = z;
+                tmat2.multiplyToRef(tmat, tmat);
+            }
+
+            if (parentBone) {
+                tmat.multiplyToRef(parentBone.getAbsoluteTransform(), tmat);
+            }
+
+            tmat.multiplyToRef(meshMat, tmat);
+
+            position.x = tmat.m[12];
+            position.y = tmat.m[13];
+            position.z = tmat.m[14];
+        }
+
+        private _getLinesForBonesWithLength(bones: Bone[], meshMat: Matrix): void {
+            var len = bones.length;
+            for (var i = 0; i < len; i++) {
+                var bone = bones[i];
+                var points = this._debugLines[i];
+                if (!points) {
+                    points = [Vector3.Zero(), Vector3.Zero()];
+                    this._debugLines[i] = points;
+                }
+                this._getBonePosition(points[0], bone, meshMat);
+                this._getBonePosition(points[1], bone, meshMat, 0, bone.length, 0);
+            }
+        }
+
+        private _getLinesForBonesNoLength(bones: Bone[], meshMat: Matrix): void {
+            var len = bones.length;
+            var boneNum = 0;
+            for (var i = len - 1; i >= 0; i--) {
+                var childBone = bones[i];
+                var parentBone = childBone.getParent();
+                if (!parentBone) {
+                    continue;
+                }
+                var points = this._debugLines[boneNum];
+                if (!points) {
+                    points = [Vector3.Zero(), Vector3.Zero()];
+                    this._debugLines[boneNum] = points;
+                }
+                this._getBonePosition(points[0], childBone, meshMat);
+                this._getBonePosition(points[1], parentBone, meshMat);
+                boneNum++;
+            }
+        }
+
+        public update() {
+            if (this.autoUpdateBonesMatrices) {
+                this._updateBoneMatrix(this.skeleton.bones[0]);
+            }
+
+            if (this.skeleton.bones[0].length === undefined) {
+                this._getLinesForBonesNoLength(this.skeleton.bones, this.mesh.getWorldMatrix());
+            } else {
+                this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
+            }
+
+            if (!this._debugMesh) {
+                this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem(null, { lines: this._debugLines, updatable: true }, this._scene);
+                this._debugMesh.renderingGroupId = this.renderingGroupId;
+            } else {
+                BABYLON.MeshBuilder.CreateLineSystem(null, { lines: this._debugLines, updatable: true, instance: this._debugMesh }, this._scene);
+            }
+            this._debugMesh.color = this.color;
+        }
+
+        private _updateBoneMatrix(bone: Bone) {
+            if (bone.getParent()) {
+                bone.getLocalMatrix().multiplyToRef(bone.getParent().getAbsoluteTransform(), bone.getAbsoluteTransform());
+            }
+
+            var children = bone.children;
+            var len = children.length;
+
+            for (var i = 0; i < len; i++) {
+                this._updateBoneMatrix(children[i]);
+            }
+        }
+
+        public dispose() {
+            if (this._debugMesh) {
+                this.isEnabled = false;
+                this._debugMesh.dispose();
+                this._debugMesh = null;
+            }
+        }
+    }
+}

+ 24 - 11
src/Layer/babylon.layer.js

@@ -31,29 +31,42 @@ var BABYLON;
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
             // Effects
             this._effect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "");
+            this._alphaTestEffect = this._scene.getEngine().createEffect("layer", ["position"], ["textureMatrix", "color", "scale", "offset"], ["textureSampler"], "#define ALPHATEST");
         }
         Layer.prototype.render = function () {
+            var currentEffect = this.alphaTest ? this._alphaTestEffect : this._effect;
             // Check
-            if (!this._effect.isReady() || !this.texture || !this.texture.isReady())
+            if (!currentEffect.isReady() || !this.texture || !this.texture.isReady())
                 return;
             var engine = this._scene.getEngine();
+            if (this.onBeforeRender) {
+                this.onBeforeRender();
+            }
             // Render
-            engine.enableEffect(this._effect);
+            engine.enableEffect(currentEffect);
             engine.setState(false);
             // Texture
-            this._effect.setTexture("textureSampler", this.texture);
-            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
+            currentEffect.setTexture("textureSampler", this.texture);
+            currentEffect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
             // Color
-            this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
+            currentEffect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
             // Scale / offset
-            this._effect.setVector2("offset", this.offset);
-            this._effect.setVector2("scale", this.scale);
+            currentEffect.setVector2("offset", this.offset);
+            currentEffect.setVector2("scale", this.scale);
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, currentEffect);
             // Draw order
-            engine.setAlphaMode(this.alphaBlendingMode);
-            engine.draw(true, 0, 6);
-            engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            if (!this._alphaTestEffect) {
+                engine.setAlphaMode(this.alphaBlendingMode);
+                engine.draw(true, 0, 6);
+                engine.setAlphaMode(BABYLON.Engine.ALPHA_DISABLE);
+            }
+            else {
+                engine.draw(true, 0, 6);
+            }
+            if (this.onAfterRender) {
+                this.onAfterRender();
+            }
         };
         Layer.prototype.dispose = function () {
             if (this._vertexBuffer) {

+ 36 - 11
src/Layer/babylon.layer.ts

@@ -6,7 +6,10 @@
         public scale = new Vector2(1, 1);
         public offset = new Vector2(0, 0);
         public onDispose: () => void;
+        public onBeforeRender: () => void;
+        public onAfterRender: () => void;
         public alphaBlendingMode = Engine.ALPHA_COMBINE;
+        public alphaTest: boolean;
 
         private _scene: Scene;
         private _vertexDeclaration = [2];
@@ -14,6 +17,7 @@
         private _vertexBuffer: WebGLBuffer;
         private _indexBuffer: WebGLBuffer;
         private _effect: Effect;
+        private _alphaTestEffect: Effect;
 
         constructor(public name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4) {
             this.texture = imgUrl ? new Texture(imgUrl, scene, true) : null;
@@ -49,37 +53,58 @@
                 ["position"],
                 ["textureMatrix", "color", "scale", "offset"],
                 ["textureSampler"], "");
+
+            this._alphaTestEffect = this._scene.getEngine().createEffect("layer",
+                ["position"],
+                ["textureMatrix", "color", "scale", "offset"],
+                ["textureSampler"], "#define ALPHATEST");
         }
 
         public render(): void {
+            var currentEffect = this.alphaTest ? this._alphaTestEffect : this._effect;
+
             // Check
-            if (!this._effect.isReady() || !this.texture || !this.texture.isReady())
+            if (!currentEffect.isReady() || !this.texture || !this.texture.isReady())
                 return;
 
             var engine = this._scene.getEngine();
 
+            if (this.onBeforeRender) {
+                this.onBeforeRender();
+            }
+
             // Render
-            engine.enableEffect(this._effect);
+            engine.enableEffect(currentEffect);
             engine.setState(false);
 
+
             // Texture
-            this._effect.setTexture("textureSampler", this.texture);
-            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
+            currentEffect.setTexture("textureSampler", this.texture);
+            currentEffect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
 
             // Color
-            this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
+            currentEffect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);
 
             // Scale / offset
-            this._effect.setVector2("offset", this.offset);
-            this._effect.setVector2("scale", this.scale);
+            currentEffect.setVector2("offset", this.offset);
+            currentEffect.setVector2("scale", this.scale);
 
             // VBOs
-            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, this._effect);
+            engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, currentEffect);
 
             // Draw order
-            engine.setAlphaMode(this.alphaBlendingMode);
-            engine.draw(true, 0, 6);
-            engine.setAlphaMode(Engine.ALPHA_DISABLE);
+            if (!this._alphaTestEffect) {
+                engine.setAlphaMode(this.alphaBlendingMode);
+                engine.draw(true, 0, 6);
+                engine.setAlphaMode(Engine.ALPHA_DISABLE);
+            }
+            else {
+                engine.draw(true, 0, 6);
+            }
+
+            if (this.onAfterRender) {
+                this.onAfterRender();
+            }
         }
 
         public dispose(): void {

+ 1 - 1
src/LensFlare/babylon.lensFlareSystem.js

@@ -85,7 +85,7 @@ var BABYLON;
                 return false;
             var engine = this._scene.getEngine();
             var viewport = this._scene.activeCamera.viewport;
-            var globalViewport = viewport.toScreenGlobal(engine);
+            var globalViewport = viewport.toGlobal(engine.getRenderWidth(true), engine.getRenderHeight(true));
             // Position
             if (!this.computeEffectivePosition(globalViewport)) {
                 return false;

+ 1 - 1
src/LensFlare/babylon.lensFlareSystem.ts

@@ -118,7 +118,7 @@
 
             var engine = this._scene.getEngine();
             var viewport = this._scene.activeCamera.viewport;
-            var globalViewport = viewport.toScreenGlobal(engine);
+            var globalViewport = viewport.toGlobal(engine.getRenderWidth(true), engine.getRenderHeight(true));
 
             // Position
             if (!this.computeEffectivePosition(globalViewport)) {

+ 4 - 1
src/Lights/babylon.light.js

@@ -95,6 +95,9 @@ var BABYLON;
             if (this.parent) {
                 serializationObject.parentId = this.parent.id;
             }
+            // Animations  
+            BABYLON.Animation.AppendSerializedAnimations(this, serializationObject);
+            serializationObject.ranges = this.serializeAnimationRanges();
             return serializationObject;
         };
         Light.GetConstructorFromName = function (type, name, scene) {
@@ -131,7 +134,7 @@ var BABYLON;
                 BABYLON.Node.ParseAnimationRanges(light, parsedLight, scene);
             }
             if (parsedLight.autoAnimate) {
-                scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, 1.0);
+                scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, parsedLight.autoAnimateSpeed || 1.0);
             }
             return light;
         };

+ 5 - 1
src/Lights/babylon.light.ts

@@ -146,6 +146,10 @@
                 serializationObject.parentId = this.parent.id;
             }
 
+            // Animations  
+            Animation.AppendSerializedAnimations(this, serializationObject);
+            serializationObject.ranges = this.serializeAnimationRanges();  
+
             return serializationObject;
         }
 
@@ -190,7 +194,7 @@
             }
 
             if (parsedLight.autoAnimate) {
-                scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, 1.0);
+                scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, parsedLight.autoAnimateSpeed || 1.0);
             }
 
             return light;

+ 3 - 0
src/Loading/Plugins/babylon.babylonFileLoader.js

@@ -214,6 +214,9 @@ var BABYLON;
                         scene.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                     }
                 }
+                if (parsedData.autoAnimate) {
+                    scene.beginAnimation(scene, parsedData.autoAnimateFrom, parsedData.autoAnimateTo, parsedData.autoAnimateLoop, parsedData.autoAnimateSpeed || 1.0);
+                }
                 // Materials
                 if (parsedData.materials) {
                     for (index = 0, cache = parsedData.materials.length; index < cache; index++) {

+ 4 - 0
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -230,6 +230,10 @@
                 }
             }
 
+            if (parsedData.autoAnimate) {
+                scene.beginAnimation(scene, parsedData.autoAnimateFrom, parsedData.autoAnimateTo, parsedData.autoAnimateLoop, parsedData.autoAnimateSpeed || 1.0);
+            }
+
             // Materials
             if (parsedData.materials) {
                 for (index = 0, cache = parsedData.materials.length; index < cache; index++) {

+ 19 - 7
src/Materials/Textures/babylon.hdrCubeTexture.js

@@ -7,21 +7,25 @@ var BABYLON;
 (function (BABYLON) {
     var HDRCubeTexture = (function (_super) {
         __extends(HDRCubeTexture, _super);
-        function HDRCubeTexture(url, scene, size, noMipmap, generateHarmonics, useInGammaSpace) {
+        function HDRCubeTexture(url, scene, size, noMipmap, generateHarmonics, useInGammaSpace, usePMREMGenerator) {
             if (noMipmap === void 0) { noMipmap = false; }
             if (generateHarmonics === void 0) { generateHarmonics = true; }
             if (useInGammaSpace === void 0) { useInGammaSpace = false; }
+            if (usePMREMGenerator === void 0) { usePMREMGenerator = false; }
             _super.call(this, scene);
             this.coordinatesMode = BABYLON.Texture.CUBIC_MODE;
             this._useInGammaSpace = false;
             this._generateHarmonics = true;
             this.sphericalPolynomial = null;
+            this.isPMREM = false;
             this.name = url;
             this.url = url;
             this._noMipmap = noMipmap;
             this.hasAlpha = false;
             this._size = size;
             this._useInGammaSpace = useInGammaSpace;
+            this._usePMREMGenerator = usePMREMGenerator && scene.getEngine().getCaps().textureLOD;
+            this.isPMREM = this._usePMREMGenerator;
             if (!url) {
                 return;
             }
@@ -84,10 +88,17 @@ var BABYLON;
                 }
                 return results;
             };
-            this._texture = this.getScene().getEngine().createRawCubeTexture(this.url, this.getScene(), this._size, BABYLON.Engine.TEXTUREFORMAT_RGB, BABYLON.Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback);
+            var mipmapGenerator = null;
+            if (!this._noMipmap && this._usePMREMGenerator) {
+                mipmapGenerator = function (data) {
+                    var generator = new BABYLON.Internals.PMREMGenerator(data, _this._size, _this._size, 0, 3, _this.getScene().getEngine().getCaps().textureFloat, 2048, 0.25, false, true);
+                    return generator.filterCubeMap();
+                };
+            }
+            this._texture = this.getScene().getEngine().createRawCubeTexture(this.url, this.getScene(), this._size, BABYLON.Engine.TEXTUREFORMAT_RGB, BABYLON.Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback, mipmapGenerator);
         };
         HDRCubeTexture.prototype.clone = function () {
-            var newTexture = new HDRCubeTexture(this.url, this.getScene(), this._size, this._noMipmap, this._generateHarmonics, this._useInGammaSpace);
+            var newTexture = new HDRCubeTexture(this.url, this.getScene(), this._size, this._noMipmap, this._generateHarmonics, this._useInGammaSpace, this._usePMREMGenerator);
             // Base texture
             newTexture.level = this.level;
             newTexture.wrapU = this.wrapU;
@@ -113,7 +124,7 @@ var BABYLON;
         HDRCubeTexture.Parse = function (parsedTexture, scene, rootUrl) {
             var texture = null;
             if (parsedTexture.name && !parsedTexture.isRenderTarget) {
-                texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size, texture.generateHarmonics, texture.useInGammaSpace);
+                texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size, texture.generateHarmonics, texture.useInGammaSpace, texture.usePMREMGenerator);
                 texture.name = parsedTexture.name;
                 texture.hasAlpha = parsedTexture.hasAlpha;
                 texture.level = parsedTexture.level;
@@ -134,14 +145,15 @@ var BABYLON;
             serializationObject.coordinatesMode = this.coordinatesMode;
             serializationObject.useInGammaSpace = this._useInGammaSpace;
             serializationObject.generateHarmonics = this._generateHarmonics;
+            serializationObject.usePMREMGenerator = this._usePMREMGenerator;
             return serializationObject;
         };
         HDRCubeTexture._facesMapping = [
-            "left",
-            "down",
-            "front",
             "right",
             "up",
+            "front",
+            "left",
+            "down",
             "back"
         ];
         return HDRCubeTexture;

+ 31 - 7
src/Materials/Textures/babylon.hdrcubetexture.ts

@@ -9,19 +9,22 @@ module BABYLON {
         private _extensions: string[];
         private _textureMatrix: Matrix;
         private _size: number;
+        private _usePMREMGenerator: boolean;
 
         private static _facesMapping = [
-            "left",
-            "down",
-            "front",
             "right",
             "up",
+            "front",
+            "left",
+            "down",
             "back"
         ];
 
         public sphericalPolynomial: SphericalPolynomial = null;
 
-        constructor(url: string, scene: Scene, size: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false) {
+        public isPMREM = false;
+
+        constructor(url: string, scene: Scene, size: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false, usePMREMGenerator = false) {
             super(scene);
 
             this.name = url;
@@ -30,6 +33,8 @@ module BABYLON {
             this.hasAlpha = false;
             this._size = size;
             this._useInGammaSpace = useInGammaSpace;
+            this._usePMREMGenerator = usePMREMGenerator && scene.getEngine().getCaps().textureLOD;
+            this.isPMREM = this._usePMREMGenerator;
 
             if (!url) {
                 return;
@@ -105,12 +110,30 @@ module BABYLON {
                 return results;
             }
 
-            this._texture = (<any>this.getScene().getEngine()).createRawCubeTexture(this.url, this.getScene(), this._size, Engine.TEXTUREFORMAT_RGB, Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback);
+            var mipmapGenerator = null;
+            if (!this._noMipmap && this._usePMREMGenerator) {
+                mipmapGenerator = (data: ArrayBufferView[]) => {
+                    var generator = new BABYLON.Internals.PMREMGenerator(data,
+                        this._size,
+                        this._size,
+                        0,
+                        3,
+                        this.getScene().getEngine().getCaps().textureFloat,
+                        2048,
+                        0.25,
+                        false,
+                        true);
+
+                    return generator.filterCubeMap();
+                };
+            }
+
+            this._texture = (<any>this.getScene().getEngine()).createRawCubeTexture(this.url, this.getScene(), this._size, Engine.TEXTUREFORMAT_RGB, Engine.TEXTURETYPE_FLOAT, this._noMipmap, callback, mipmapGenerator);
         }
 
         public clone(): HDRCubeTexture {
             var newTexture = new HDRCubeTexture(this.url, this.getScene(), this._size, this._noMipmap,
-                this._generateHarmonics, this._useInGammaSpace);
+                this._generateHarmonics, this._useInGammaSpace, this._usePMREMGenerator);
 
             // Base texture
             newTexture.level = this.level;
@@ -144,7 +167,7 @@ module BABYLON {
             var texture = null;
             if (parsedTexture.name && !parsedTexture.isRenderTarget) {
                 texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, parsedTexture.size,
-                    texture.generateHarmonics, texture.useInGammaSpace);
+                    texture.generateHarmonics, texture.useInGammaSpace, texture.usePMREMGenerator);
                 texture.name = parsedTexture.name;
                 texture.hasAlpha = parsedTexture.hasAlpha;
                 texture.level = parsedTexture.level;
@@ -167,6 +190,7 @@ module BABYLON {
             serializationObject.coordinatesMode = this.coordinatesMode;
             serializationObject.useInGammaSpace = this._useInGammaSpace;
             serializationObject.generateHarmonics = this._generateHarmonics;
+            serializationObject.usePMREMGenerator = this._usePMREMGenerator;
 
             return serializationObject;
         }

+ 23 - 6
src/Materials/babylon.effect.js

@@ -189,7 +189,7 @@ var BABYLON;
         };
         Effect.prototype._processIncludes = function (sourceCode, callback) {
             var _this = this;
-            var regex = /#include<(.+)>(\((.*)\))*/g;
+            var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
             var match = regex.exec(sourceCode);
             var returnValue = new String(sourceCode);
             while (match != null) {
@@ -198,13 +198,16 @@ var BABYLON;
                     // Substitution
                     var includeContent = Effect.IncludesShadersStore[includeFile];
                     if (match[2]) {
-                        var splits = match[2].substr(1, match[2].length - 2).split(",");
+                        var splits = match[3].split(",");
                         for (var index = 0; index < splits.length; index += 2) {
                             var source = new RegExp(splits[index], "g");
                             var dest = splits[index + 1];
                             includeContent = includeContent.replace(source, dest);
                         }
                     }
+                    if (match[4]) {
+                        includeContent = includeContent.replace(/\{X\}/g, match[5]);
+                    }
                     // Replace
                     returnValue = returnValue.replace(match[0], includeContent);
                 }
@@ -220,14 +223,28 @@ var BABYLON;
             }
             callback(returnValue);
         };
+        Effect.prototype._processPrecision = function (source) {
+            if (source.indexOf("precision highp float") === -1) {
+                if (!this._engine.getCaps().highPrecisionShaderSupported) {
+                    source = "precision mediump float;\n" + source;
+                }
+                else {
+                    source = "precision highp float;\n" + source;
+                }
+            }
+            else {
+                if (!this._engine.getCaps().highPrecisionShaderSupported) {
+                    source = source.replace("precision highp float", "precision mediump float");
+                }
+            }
+            return source;
+        };
         Effect.prototype._prepareEffect = function (vertexSourceCode, fragmentSourceCode, attributesNames, defines, fallbacks) {
             try {
                 var engine = this._engine;
                 // Precision
-                if (!engine.getCaps().highPrecisionShaderSupported) {
-                    vertexSourceCode = vertexSourceCode.replace("precision highp float", "precision mediump float");
-                    fragmentSourceCode = fragmentSourceCode.replace("precision highp float", "precision mediump float");
-                }
+                vertexSourceCode = this._processPrecision(vertexSourceCode);
+                fragmentSourceCode = this._processPrecision(fragmentSourceCode);
                 this._program = engine.createShaderProgram(vertexSourceCode, fragmentSourceCode, defines);
                 this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
                 this._attributes = engine.getAttributes(this._program, attributesNames);

+ 26 - 8
src/Materials/babylon.effect.ts

@@ -237,7 +237,7 @@
         }
 
         private _processIncludes(sourceCode: string, callback: (data: any) => void): void {
-            var regex = /#include<(.+)>(\((.*)\))*/g;
+            var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
             var match = regex.exec(sourceCode);
 
             var returnValue = new String(sourceCode);
@@ -249,8 +249,8 @@
                     // Substitution
                     var includeContent = Effect.IncludesShadersStore[includeFile];
                     if (match[2]) {
-                        var splits = match[2].substr(1, match[2].length - 2).split(",");
-
+                        var splits = match[3].split(",");
+                      
                         for (var index = 0; index < splits.length; index += 2) {
                             var source = new RegExp(splits[index], "g");
                             var dest = splits[index + 1];
@@ -259,6 +259,10 @@
                         }
                     }
 
+                    if (match[4]) {
+                        includeContent = includeContent.replace(/\{X\}/g, match[5]);
+                    }
+
                     // Replace
                     returnValue = returnValue.replace(match[0], includeContent);
                 } else {
@@ -277,16 +281,30 @@
             callback(returnValue);
         }
 
+        private _processPrecision(source: string): string {
+            if (source.indexOf("precision highp float") === -1) {
+                if (!this._engine.getCaps().highPrecisionShaderSupported) {
+                    source = "precision mediump float;\n" + source;
+                } else {
+                    source = "precision highp float;\n" + source;
+                }
+            } else {
+                if (!this._engine.getCaps().highPrecisionShaderSupported) { // Moving highp to mediump
+                    source = source.replace("precision highp float", "precision mediump float");
+                }
+            }
+
+            return source;
+        }
+
         private _prepareEffect(vertexSourceCode: string, fragmentSourceCode: string, attributesNames: string[], defines: string, fallbacks?: EffectFallbacks): void {
             try {
                 var engine = this._engine;
 
                 // Precision
-                if (!engine.getCaps().highPrecisionShaderSupported) { // Moving highp to mediump
-                    vertexSourceCode = vertexSourceCode.replace("precision highp float", "precision mediump float");
-                    fragmentSourceCode = fragmentSourceCode.replace("precision highp float", "precision mediump float");
-                }
-
+                vertexSourceCode = this._processPrecision(vertexSourceCode);
+                fragmentSourceCode = this._processPrecision(fragmentSourceCode);
+                
                 this._program = engine.createShaderProgram(vertexSourceCode, fragmentSourceCode, defines);
 
                 this._uniforms = engine.getUniforms(this._program, this._uniformsNames);

+ 80 - 267
src/Math/babylon.math.js

@@ -2,6 +2,38 @@ var BABYLON;
 (function (BABYLON) {
     BABYLON.ToGammaSpace = 1 / 2.2;
     BABYLON.ToLinearSpace = 2.2;
+    BABYLON.Epsilon = 0.001;
+    var MathTools = (function () {
+        function MathTools() {
+        }
+        MathTools.WithinEpsilon = function (a, b, epsilon) {
+            if (epsilon === void 0) { epsilon = 1.401298E-45; }
+            var num = a - b;
+            return -epsilon <= num && num <= epsilon;
+        };
+        MathTools.ToHex = function (i) {
+            var str = i.toString(16);
+            if (i <= 15) {
+                return ("0" + str).toUpperCase();
+            }
+            return str.toUpperCase();
+        };
+        // Returns -1 when value is a negative number and
+        // +1 when value is a positive number. 
+        MathTools.Sign = function (value) {
+            value = +value; // convert to a number
+            if (value === 0 || isNaN(value))
+                return value;
+            return value > 0 ? 1 : -1;
+        };
+        MathTools.Clamp = function (value, min, max) {
+            if (min === void 0) { min = 0; }
+            if (max === void 0) { max = 1; }
+            return Math.min(max, Math.max(min, value));
+        };
+        return MathTools;
+    })();
+    BABYLON.MathTools = MathTools;
     var Color3 = (function () {
         function Color3(r, g, b) {
             if (r === void 0) { r = 0; }
@@ -97,7 +129,7 @@ var BABYLON;
             var intR = (this.r * 255) | 0;
             var intG = (this.g * 255) | 0;
             var intB = (this.b * 255) | 0;
-            return "#" + BABYLON.Tools.ToHex(intR) + BABYLON.Tools.ToHex(intG) + BABYLON.Tools.ToHex(intB);
+            return "#" + MathTools.ToHex(intR) + MathTools.ToHex(intG) + MathTools.ToHex(intB);
         };
         Color3.prototype.toLinearSpace = function () {
             var convertedColor = new Color3();
@@ -124,7 +156,7 @@ var BABYLON;
         // Statics
         Color3.FromHexString = function (hex) {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
-                BABYLON.Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
+                //Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
                 return new Color3(0, 0, 0);
             }
             var r = parseInt(hex.substring(1, 3), 16);
@@ -228,12 +260,12 @@ var BABYLON;
             var intG = (this.g * 255) | 0;
             var intB = (this.b * 255) | 0;
             var intA = (this.a * 255) | 0;
-            return "#" + BABYLON.Tools.ToHex(intR) + BABYLON.Tools.ToHex(intG) + BABYLON.Tools.ToHex(intB) + BABYLON.Tools.ToHex(intA);
+            return "#" + MathTools.ToHex(intR) + MathTools.ToHex(intG) + MathTools.ToHex(intB) + MathTools.ToHex(intA);
         };
         // Statics
         Color4.FromHexString = function (hex) {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
-                BABYLON.Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
+                //Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
                 return new Color4(0, 0, 0, 0);
             }
             var r = parseInt(hex.substring(1, 3), 16);
@@ -361,8 +393,8 @@ var BABYLON;
             return otherVector && this.x === otherVector.x && this.y === otherVector.y;
         };
         Vector2.prototype.equalsWithEpsilon = function (otherVector, epsilon) {
-            if (epsilon === void 0) { epsilon = BABYLON.Engine.Epsilon; }
-            return otherVector && BABYLON.Tools.WithinEpsilon(this.x, otherVector.x, epsilon) && BABYLON.Tools.WithinEpsilon(this.y, otherVector.y, epsilon);
+            if (epsilon === void 0) { epsilon = BABYLON.Epsilon; }
+            return otherVector && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon) && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon);
         };
         // Properties
         Vector2.prototype.length = function () {
@@ -562,8 +594,8 @@ var BABYLON;
             return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z;
         };
         Vector3.prototype.equalsWithEpsilon = function (otherVector, epsilon) {
-            if (epsilon === void 0) { epsilon = BABYLON.Engine.Epsilon; }
-            return otherVector && BABYLON.Tools.WithinEpsilon(this.x, otherVector.x, epsilon) && BABYLON.Tools.WithinEpsilon(this.y, otherVector.y, epsilon) && BABYLON.Tools.WithinEpsilon(this.z, otherVector.z, epsilon);
+            if (epsilon === void 0) { epsilon = BABYLON.Epsilon; }
+            return otherVector && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon) && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon) && MathTools.WithinEpsilon(this.z, otherVector.z, epsilon);
         };
         Vector3.prototype.equalsToFloats = function (x, y, z) {
             return this.x === x && this.y === y && this.z === z;
@@ -806,7 +838,7 @@ var BABYLON;
             source.y = -(source.y / viewportHeight * 2 - 1);
             var vector = Vector3.TransformCoordinates(source, matrix);
             var num = source.x * matrix.m[3] + source.y * matrix.m[7] + source.z * matrix.m[11] + matrix.m[15];
-            if (BABYLON.Tools.WithinEpsilon(num, 1.0)) {
+            if (MathTools.WithinEpsilon(num, 1.0)) {
                 vector = vector.scale(1.0 / num);
             }
             return vector;
@@ -817,7 +849,7 @@ var BABYLON;
             var screenSource = new Vector3(source.x / viewportWidth * 2 - 1, -(source.y / viewportHeight * 2 - 1), source.z);
             var vector = Vector3.TransformCoordinates(screenSource, matrix);
             var num = screenSource.x * matrix.m[3] + screenSource.y * matrix.m[7] + screenSource.z * matrix.m[11] + matrix.m[15];
-            if (BABYLON.Tools.WithinEpsilon(num, 1.0)) {
+            if (MathTools.WithinEpsilon(num, 1.0)) {
                 vector = vector.scale(1.0 / num);
             }
             return vector;
@@ -881,10 +913,10 @@ var BABYLON;
             // Rv3(u) = u1, and u1 belongs to plane xOz
             // Rv3(w) = w1 = w invariant
             var u1 = Tmp.Vector3[1];
-            if (BABYLON.Tools.WithinEpsilon(w.z, 0, BABYLON.Engine.Epsilon)) {
+            if (MathTools.WithinEpsilon(w.z, 0, BABYLON.Epsilon)) {
                 z = 1.0;
             }
-            else if (BABYLON.Tools.WithinEpsilon(w.x, 0, BABYLON.Engine.Epsilon)) {
+            else if (MathTools.WithinEpsilon(w.x, 0, BABYLON.Epsilon)) {
                 x = 1.0;
             }
             else {
@@ -918,7 +950,7 @@ var BABYLON;
             y = 0.0;
             z = 0.0;
             sign = -1.0;
-            if (BABYLON.Tools.WithinEpsilon(w.z, 0, BABYLON.Engine.Epsilon)) {
+            if (MathTools.WithinEpsilon(w.z, 0, BABYLON.Epsilon)) {
                 x = 1.0;
             }
             else {
@@ -1059,12 +1091,12 @@ var BABYLON;
             return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z && this.w === otherVector.w;
         };
         Vector4.prototype.equalsWithEpsilon = function (otherVector, epsilon) {
-            if (epsilon === void 0) { epsilon = BABYLON.Engine.Epsilon; }
+            if (epsilon === void 0) { epsilon = BABYLON.Epsilon; }
             return otherVector
-                && BABYLON.Tools.WithinEpsilon(this.x, otherVector.x, epsilon)
-                && BABYLON.Tools.WithinEpsilon(this.y, otherVector.y, epsilon)
-                && BABYLON.Tools.WithinEpsilon(this.z, otherVector.z, epsilon)
-                && BABYLON.Tools.WithinEpsilon(this.w, otherVector.w, epsilon);
+                && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon)
+                && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon)
+                && MathTools.WithinEpsilon(this.z, otherVector.z, epsilon)
+                && MathTools.WithinEpsilon(this.w, otherVector.w, epsilon);
         };
         Vector4.prototype.equalsToFloats = function (x, y, z, w) {
             return this.x === x && this.y === y && this.z === z && this.w === w;
@@ -1285,6 +1317,20 @@ var BABYLON;
             this.multiplyToRef(q1, this);
             return this;
         };
+        Quaternion.prototype.conjugateToRef = function (ref) {
+            ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
+            return this;
+        };
+        Quaternion.prototype.conjugateInPlace = function () {
+            this.x *= -1;
+            this.y *= -1;
+            this.z *= -1;
+            return this;
+        };
+        Quaternion.prototype.conjugate = function () {
+            var result = new Quaternion(-this.x, -this.y, -this.z, this.w);
+            return result;
+        };
         Quaternion.prototype.length = function () {
             return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w));
         };
@@ -1705,9 +1751,9 @@ var BABYLON;
             translation.x = this.m[12];
             translation.y = this.m[13];
             translation.z = this.m[14];
-            var xs = BABYLON.Tools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
-            var ys = BABYLON.Tools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
-            var zs = BABYLON.Tools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
+            var xs = MathTools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
+            var ys = MathTools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
+            var zs = MathTools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
             scale.x = xs * Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1] + this.m[2] * this.m[2]);
             scale.y = ys * Math.sqrt(this.m[4] * this.m[4] + this.m[5] * this.m[5] + this.m[6] * this.m[6]);
             scale.z = zs * Math.sqrt(this.m[8] * this.m[8] + this.m[9] * this.m[9] + this.m[10] * this.m[10]);
@@ -2027,18 +2073,17 @@ var BABYLON;
             Matrix.PerspectiveFovLHToRef(fov, aspect, znear, zfar, matrix);
             return matrix;
         };
-        Matrix.PerspectiveFovLHToRef = function (fov, aspect, znear, zfar, result, fovMode) {
-            if (fovMode === void 0) { fovMode = BABYLON.Camera.FOVMODE_VERTICAL_FIXED; }
+        Matrix.PerspectiveFovLHToRef = function (fov, aspect, znear, zfar, result, isVerticalFovFixed) {
+            if (isVerticalFovFixed === void 0) { isVerticalFovFixed = true; }
             var tan = 1.0 / (Math.tan(fov * 0.5));
-            var v_fixed = (fovMode === BABYLON.Camera.FOVMODE_VERTICAL_FIXED);
-            if (v_fixed) {
+            if (isVerticalFovFixed) {
                 result.m[0] = tan / aspect;
             }
             else {
                 result.m[0] = tan;
             }
             result.m[1] = result.m[2] = result.m[3] = 0.0;
-            if (v_fixed) {
+            if (isVerticalFovFixed) {
                 result.m[5] = tan;
             }
             else {
@@ -2229,15 +2274,8 @@ var BABYLON;
             this.width = width;
             this.height = height;
         }
-        Viewport.prototype.toGlobal = function (engine) {
-            var width = engine.getRenderWidth();
-            var height = engine.getRenderHeight();
-            return new Viewport(this.x * width, this.y * height, this.width * width, this.height * height);
-        };
-        Viewport.prototype.toScreenGlobal = function (engine) {
-            var width = engine.getRenderWidth(true);
-            var height = engine.getRenderHeight(true);
-            return new Viewport(this.x * width, this.y * height, this.width * width, this.height * height);
+        Viewport.prototype.toGlobal = function (renderWidth, renderHeight) {
+            return new Viewport(this.x * renderWidth, this.y * renderHeight, this.width * renderWidth, this.height * renderHeight);
         };
         return Viewport;
     })();
@@ -2294,174 +2332,6 @@ var BABYLON;
         return Frustum;
     })();
     BABYLON.Frustum = Frustum;
-    var Ray = (function () {
-        function Ray(origin, direction, length) {
-            if (length === void 0) { length = Number.MAX_VALUE; }
-            this.origin = origin;
-            this.direction = direction;
-            this.length = length;
-        }
-        // Methods
-        Ray.prototype.intersectsBoxMinMax = function (minimum, maximum) {
-            var d = 0.0;
-            var maxValue = Number.MAX_VALUE;
-            var inv;
-            var min;
-            var max;
-            var temp;
-            if (Math.abs(this.direction.x) < 0.0000001) {
-                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.x;
-                min = (minimum.x - this.origin.x) * inv;
-                max = (maximum.x - this.origin.x) * inv;
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-            if (Math.abs(this.direction.y) < 0.0000001) {
-                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.y;
-                min = (minimum.y - this.origin.y) * inv;
-                max = (maximum.y - this.origin.y) * inv;
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-            if (Math.abs(this.direction.z) < 0.0000001) {
-                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.z;
-                min = (minimum.z - this.origin.z) * inv;
-                max = (maximum.z - this.origin.z) * inv;
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-            return true;
-        };
-        Ray.prototype.intersectsBox = function (box) {
-            return this.intersectsBoxMinMax(box.minimum, box.maximum);
-        };
-        Ray.prototype.intersectsSphere = function (sphere) {
-            var x = sphere.center.x - this.origin.x;
-            var y = sphere.center.y - this.origin.y;
-            var z = sphere.center.z - this.origin.z;
-            var pyth = (x * x) + (y * y) + (z * z);
-            var rr = sphere.radius * sphere.radius;
-            if (pyth <= rr) {
-                return true;
-            }
-            var dot = (x * this.direction.x) + (y * this.direction.y) + (z * this.direction.z);
-            if (dot < 0.0) {
-                return false;
-            }
-            var temp = pyth - (dot * dot);
-            return temp <= rr;
-        };
-        Ray.prototype.intersectsTriangle = function (vertex0, vertex1, vertex2) {
-            if (!this._edge1) {
-                this._edge1 = Vector3.Zero();
-                this._edge2 = Vector3.Zero();
-                this._pvec = Vector3.Zero();
-                this._tvec = Vector3.Zero();
-                this._qvec = Vector3.Zero();
-            }
-            vertex1.subtractToRef(vertex0, this._edge1);
-            vertex2.subtractToRef(vertex0, this._edge2);
-            Vector3.CrossToRef(this.direction, this._edge2, this._pvec);
-            var det = Vector3.Dot(this._edge1, this._pvec);
-            if (det === 0) {
-                return null;
-            }
-            var invdet = 1 / det;
-            this.origin.subtractToRef(vertex0, this._tvec);
-            var bu = Vector3.Dot(this._tvec, this._pvec) * invdet;
-            if (bu < 0 || bu > 1.0) {
-                return null;
-            }
-            Vector3.CrossToRef(this._tvec, this._edge1, this._qvec);
-            var bv = Vector3.Dot(this.direction, this._qvec) * invdet;
-            if (bv < 0 || bu + bv > 1.0) {
-                return null;
-            }
-            //check if the distance is longer than the predefined length.
-            var distance = Vector3.Dot(this._edge2, this._qvec) * invdet;
-            if (distance > this.length) {
-                return null;
-            }
-            return new BABYLON.IntersectionInfo(bu, bv, distance);
-        };
-        // Statics
-        Ray.CreateNew = function (x, y, viewportWidth, viewportHeight, world, view, projection) {
-            var start = Vector3.Unproject(new Vector3(x, y, 0), viewportWidth, viewportHeight, world, view, projection);
-            var end = Vector3.Unproject(new Vector3(x, y, 1), viewportWidth, viewportHeight, world, view, projection);
-            var direction = end.subtract(start);
-            direction.normalize();
-            return new Ray(start, direction);
-        };
-        /**
-        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
-        * transformed to the given world matrix.
-        * @param origin The origin point
-        * @param end The end point
-        * @param world a matrix to transform the ray to. Default is the identity matrix.
-        */
-        Ray.CreateNewFromTo = function (origin, end, world) {
-            if (world === void 0) { world = Matrix.Identity(); }
-            var direction = end.subtract(origin);
-            var length = Math.sqrt((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z));
-            direction.normalize();
-            return Ray.Transform(new Ray(origin, direction, length), world);
-        };
-        Ray.Transform = function (ray, matrix) {
-            var newOrigin = Vector3.TransformCoordinates(ray.origin, matrix);
-            var newDirection = Vector3.TransformNormal(ray.direction, matrix);
-            return new Ray(newOrigin, newDirection, ray.length);
-        };
-        return Ray;
-    })();
-    BABYLON.Ray = Ray;
     (function (Space) {
         Space[Space["LOCAL"] = 0] = "LOCAL";
         Space[Space["WORLD"] = 1] = "WORLD";
@@ -2560,63 +2430,6 @@ var BABYLON;
         return Arc2;
     })();
     BABYLON.Arc2 = Arc2;
-    var PathCursor = (function () {
-        function PathCursor(path) {
-            this.path = path;
-            this._onchange = new Array();
-            this.value = 0;
-            this.animations = new Array();
-        }
-        PathCursor.prototype.getPoint = function () {
-            var point = this.path.getPointAtLengthPosition(this.value);
-            return new Vector3(point.x, 0, point.y);
-        };
-        PathCursor.prototype.moveAhead = function (step) {
-            if (step === void 0) { step = 0.002; }
-            this.move(step);
-            return this;
-        };
-        PathCursor.prototype.moveBack = function (step) {
-            if (step === void 0) { step = 0.002; }
-            this.move(-step);
-            return this;
-        };
-        PathCursor.prototype.move = function (step) {
-            if (Math.abs(step) > 1) {
-                throw "step size should be less than 1.";
-            }
-            this.value += step;
-            this.ensureLimits();
-            this.raiseOnChange();
-            return this;
-        };
-        PathCursor.prototype.ensureLimits = function () {
-            while (this.value > 1) {
-                this.value -= 1;
-            }
-            while (this.value < 0) {
-                this.value += 1;
-            }
-            return this;
-        };
-        // used by animation engine
-        PathCursor.prototype.markAsDirty = function (propertyName) {
-            this.ensureLimits();
-            this.raiseOnChange();
-            return this;
-        };
-        PathCursor.prototype.raiseOnChange = function () {
-            var _this = this;
-            this._onchange.forEach(function (f) { return f(_this); });
-            return this;
-        };
-        PathCursor.prototype.onchange = function (f) {
-            this._onchange.push(f);
-            return this;
-        };
-        return PathCursor;
-    })();
-    BABYLON.PathCursor = PathCursor;
     var Path2 = (function () {
         function Path2(x, y) {
             this._points = new Array();
@@ -2626,7 +2439,7 @@ var BABYLON;
         }
         Path2.prototype.addLineTo = function (x, y) {
             if (closed) {
-                BABYLON.Tools.Error("cannot add lines to closed paths");
+                //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
             var newPoint = new Vector2(x, y);
@@ -2638,7 +2451,7 @@ var BABYLON;
         Path2.prototype.addArcTo = function (midX, midY, endX, endY, numberOfSegments) {
             if (numberOfSegments === void 0) { numberOfSegments = 36; }
             if (closed) {
-                BABYLON.Tools.Error("cannot add arcs to closed paths");
+                //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }
             var startPoint = this._points[this._points.length - 1];
@@ -2675,7 +2488,7 @@ var BABYLON;
         };
         Path2.prototype.getPointAtLengthPosition = function (normalizedLengthPosition) {
             if (normalizedLengthPosition < 0 || normalizedLengthPosition > 1) {
-                BABYLON.Tools.Error("normalized length position should be between 0 and 1.");
+                //Tools.Error("normalized length position should be between 0 and 1.");
                 return Vector2.Zero();
             }
             var lengthPosition = normalizedLengthPosition * this.length();
@@ -2693,7 +2506,7 @@ var BABYLON;
                 }
                 previousOffset = nextOffset;
             }
-            BABYLON.Tools.Error("internal error");
+            //Tools.Error("internal error");
             return Vector2.Zero();
         };
         Path2.StartingAt = function (x, y) {
@@ -2828,13 +2641,13 @@ var BABYLON;
             var normal0;
             if (va === undefined || va === null) {
                 var point;
-                if (!BABYLON.Tools.WithinEpsilon(vt.y, 1, BABYLON.Engine.Epsilon)) {
+                if (!MathTools.WithinEpsilon(vt.y, 1, BABYLON.Epsilon)) {
                     point = new Vector3(0, -1, 0);
                 }
-                else if (!BABYLON.Tools.WithinEpsilon(vt.x, 1, BABYLON.Engine.Epsilon)) {
+                else if (!MathTools.WithinEpsilon(vt.x, 1, BABYLON.Epsilon)) {
                     point = new Vector3(1, 0, 0);
                 }
-                else if (!BABYLON.Tools.WithinEpsilon(vt.z, 1, BABYLON.Engine.Epsilon)) {
+                else if (!MathTools.WithinEpsilon(vt.z, 1, BABYLON.Epsilon)) {
                     point = new Vector3(0, 0, 1);
                 }
                 normal0 = Vector3.Cross(vt, point);

+ 87 - 324
src/Math/babylon.math.ts

@@ -4,6 +4,41 @@
 
     export const ToGammaSpace = 1 / 2.2;
     export const ToLinearSpace = 2.2;
+    export const Epsilon = 0.001;
+
+
+    export class MathTools {
+        public static WithinEpsilon(a: number, b: number, epsilon: number = 1.401298E-45): boolean {
+            var num = a - b;
+            return -epsilon <= num && num <= epsilon;
+        }
+
+        public static ToHex(i: number): string {
+            var str = i.toString(16);
+
+            if (i <= 15) {
+                return ("0" + str).toUpperCase();
+            }
+
+            return str.toUpperCase();
+        }
+        
+        // Returns -1 when value is a negative number and
+        // +1 when value is a positive number. 
+        public static Sign(value: number): number {
+            value = +value; // convert to a number
+
+            if (value === 0 || isNaN(value))
+                return value;
+
+            return value > 0 ? 1 : -1;
+        }
+
+        public static Clamp(value: number, min = 0, max = 1): number {
+            return Math.min(max, Math.max(min, value));
+        }
+    }
+
 
     export class Color3 {
         constructor(public r: number = 0, public g: number = 0, public b: number = 0) {
@@ -123,7 +158,7 @@
             var intG = (this.g * 255) | 0;
             var intB = (this.b * 255) | 0;
 
-            return "#" + Tools.ToHex(intR) + Tools.ToHex(intG) + Tools.ToHex(intB);
+            return "#" + MathTools.ToHex(intR) + MathTools.ToHex(intG) + MathTools.ToHex(intB);
         }
 
         public toLinearSpace(): Color3 {
@@ -157,7 +192,7 @@
         // Statics
         public static FromHexString(hex: string): Color3 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
-                Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
+                //Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
                 return new Color3(0, 0, 0);
             }
 
@@ -282,13 +317,13 @@
             var intB = (this.b * 255) | 0;
             var intA = (this.a * 255) | 0;
 
-            return "#" + Tools.ToHex(intR) + Tools.ToHex(intG) + Tools.ToHex(intB) + Tools.ToHex(intA);
+            return "#" + MathTools.ToHex(intR) + MathTools.ToHex(intG) + MathTools.ToHex(intB) + MathTools.ToHex(intA);
         }
 
         // Statics
         public static FromHexString(hex: string): Color4 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
-                Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
+                //Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
                 return new Color4(0, 0, 0, 0);
             }
 
@@ -450,8 +485,8 @@
             return otherVector && this.x === otherVector.x && this.y === otherVector.y;
         }
 
-        public equalsWithEpsilon(otherVector: Vector2, epsilon: number = Engine.Epsilon): boolean {
-            return otherVector && Tools.WithinEpsilon(this.x, otherVector.x, epsilon) && Tools.WithinEpsilon(this.y, otherVector.y, epsilon);
+        public equalsWithEpsilon(otherVector: Vector2, epsilon: number = Epsilon): boolean {
+            return otherVector && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon) && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon);
         }
 
         // Properties
@@ -591,7 +626,7 @@
     export class Vector3 {
 
         constructor(public x: number, public y: number, public z: number) {
-            
+
         }
 
         public toString(): string {
@@ -710,8 +745,8 @@
             return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z;
         }
 
-        public equalsWithEpsilon(otherVector: Vector3, epsilon: number = Engine.Epsilon): boolean {
-            return otherVector && Tools.WithinEpsilon(this.x, otherVector.x, epsilon) && Tools.WithinEpsilon(this.y, otherVector.y, epsilon) && Tools.WithinEpsilon(this.z, otherVector.z, epsilon);
+        public equalsWithEpsilon(otherVector: Vector3, epsilon: number = Epsilon): boolean {
+            return otherVector && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon) && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon) && MathTools.WithinEpsilon(this.z, otherVector.z, epsilon);
         }
 
         public equalsToFloats(x: number, y: number, z: number): boolean {
@@ -1029,7 +1064,7 @@
             var vector = Vector3.TransformCoordinates(source, matrix);
             var num = source.x * matrix.m[3] + source.y * matrix.m[7] + source.z * matrix.m[11] + matrix.m[15];
 
-            if (Tools.WithinEpsilon(num, 1.0)) {
+            if (MathTools.WithinEpsilon(num, 1.0)) {
                 vector = vector.scale(1.0 / num);
             }
 
@@ -1043,7 +1078,7 @@
             var vector = Vector3.TransformCoordinates(screenSource, matrix);
             var num = screenSource.x * matrix.m[3] + screenSource.y * matrix.m[7] + screenSource.z * matrix.m[11] + matrix.m[15];
 
-            if (Tools.WithinEpsilon(num, 1.0)) {
+            if (MathTools.WithinEpsilon(num, 1.0)) {
                 vector = vector.scale(1.0 / num);
             }
 
@@ -1119,10 +1154,10 @@
             // Rv3(u) = u1, and u1 belongs to plane xOz
             // Rv3(w) = w1 = w invariant
             var u1: Vector3 = Tmp.Vector3[1];
-            if (Tools.WithinEpsilon(w.z, 0, Engine.Epsilon)) {
+            if (MathTools.WithinEpsilon(w.z, 0, Epsilon)) {
                 z = 1.0;
             }
-            else if (Tools.WithinEpsilon(w.x, 0, Engine.Epsilon)) {
+            else if (MathTools.WithinEpsilon(w.x, 0, Epsilon)) {
                 x = 1.0;
             }
             else {
@@ -1160,7 +1195,7 @@
             y = 0.0;
             z = 0.0;
             sign = -1.0;
-            if (Tools.WithinEpsilon(w.z, 0, Engine.Epsilon)) {
+            if (MathTools.WithinEpsilon(w.z, 0, Epsilon)) {
                 x = 1.0;
             }
             else {
@@ -1325,12 +1360,12 @@
             return otherVector && this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z && this.w === otherVector.w;
         }
 
-        public equalsWithEpsilon(otherVector: Vector4, epsilon: number = Engine.Epsilon): boolean {
+        public equalsWithEpsilon(otherVector: Vector4, epsilon: number = Epsilon): boolean {
             return otherVector
-                && Tools.WithinEpsilon(this.x, otherVector.x, epsilon)
-                && Tools.WithinEpsilon(this.y, otherVector.y, epsilon)
-                && Tools.WithinEpsilon(this.z, otherVector.z, epsilon)
-                && Tools.WithinEpsilon(this.w, otherVector.w, epsilon);
+                && MathTools.WithinEpsilon(this.x, otherVector.x, epsilon)
+                && MathTools.WithinEpsilon(this.y, otherVector.y, epsilon)
+                && MathTools.WithinEpsilon(this.z, otherVector.z, epsilon)
+                && MathTools.WithinEpsilon(this.w, otherVector.w, epsilon);
         }
 
         public equalsToFloats(x: number, y: number, z: number, w: number): boolean {
@@ -1593,6 +1628,23 @@
             return this;
         }
 
+        public conjugateToRef(ref: Quaternion): Quaternion {
+            ref.copyFromFloats(-this.x, -this.y, -this.z, this.w);
+            return this;
+        }
+
+        public conjugateInPlace(): Quaternion {
+            this.x *= -1;
+            this.y *= -1;
+            this.z *= -1;
+            return this;
+        }
+
+        public conjugate(): Quaternion {
+            var result = new Quaternion(-this.x, -this.y, -this.z, this.w);
+            return result;
+        }
+
         public length(): number {
             return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w));
         }
@@ -2100,9 +2152,9 @@
             translation.y = this.m[13];
             translation.z = this.m[14];
 
-            var xs = Tools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
-            var ys = Tools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
-            var zs = Tools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
+            var xs = MathTools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
+            var ys = MathTools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
+            var zs = MathTools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
 
             scale.x = xs * Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1] + this.m[2] * this.m[2]);
             scale.y = ys * Math.sqrt(this.m[4] * this.m[4] + this.m[5] * this.m[5] + this.m[6] * this.m[6]);
@@ -2549,12 +2601,10 @@
             return matrix;
         }
 
-        public static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, fovMode = Camera.FOVMODE_VERTICAL_FIXED): void {
+        public static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed = true): void {
             var tan = 1.0 / (Math.tan(fov * 0.5));
-
-            var v_fixed = (fovMode === Camera.FOVMODE_VERTICAL_FIXED);
-
-            if (v_fixed) {
+            
+            if (isVerticalFovFixed) {
                 result.m[0] = tan / aspect;
             }
             else {
@@ -2563,7 +2613,7 @@
 
             result.m[1] = result.m[2] = result.m[3] = 0.0;
 
-            if (v_fixed) {
+            if (isVerticalFovFixed) {
                 result.m[5] = tan;
             }
             else {
@@ -2795,16 +2845,8 @@
         constructor(public x: number, public y: number, public width: number, public height: number) {
         }
 
-        public toGlobal(engine: Engine): Viewport {
-            var width = engine.getRenderWidth();
-            var height = engine.getRenderHeight();
-            return new Viewport(this.x * width, this.y * height, this.width * width, this.height * height);
-        }
-
-        public toScreenGlobal(engine: Engine): Viewport {
-            var width = engine.getRenderWidth(true);
-            var height = engine.getRenderHeight(true);
-            return new Viewport(this.x * width, this.y * height, this.width * width, this.height * height);
+        public toGlobal(renderWidth: number, renderHeight: number): Viewport {
+            return new Viewport(this.x * renderWidth, this.y * renderHeight, this.width * renderWidth, this.height * renderHeight);
         }
     }
 
@@ -2866,213 +2908,6 @@
         }
     }
 
-    export class Ray {
-        private _edge1: Vector3;
-        private _edge2: Vector3;
-        private _pvec: Vector3;
-        private _tvec: Vector3;
-        private _qvec: Vector3;
-
-        constructor(public origin: Vector3, public direction: Vector3, public length: number = Number.MAX_VALUE) {
-        }
-
-        // Methods
-        public intersectsBoxMinMax(minimum: Vector3, maximum: Vector3): boolean {
-            var d = 0.0;
-            var maxValue = Number.MAX_VALUE;
-            var inv: number;
-            var min: number;
-            var max: number;
-            var temp: number;
-            if (Math.abs(this.direction.x) < 0.0000001) {
-                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.x;
-                min = (minimum.x - this.origin.x) * inv;
-                max = (maximum.x - this.origin.x) * inv;
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-
-            if (Math.abs(this.direction.y) < 0.0000001) {
-                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.y;
-                min = (minimum.y - this.origin.y) * inv;
-                max = (maximum.y - this.origin.y) * inv;
-
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-
-            if (Math.abs(this.direction.z) < 0.0000001) {
-                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
-                    return false;
-                }
-            }
-            else {
-                inv = 1.0 / this.direction.z;
-                min = (minimum.z - this.origin.z) * inv;
-                max = (maximum.z - this.origin.z) * inv;
-
-                if (max === -Infinity) {
-                    max = Infinity;
-                }
-
-                if (min > max) {
-                    temp = min;
-                    min = max;
-                    max = temp;
-                }
-
-                d = Math.max(min, d);
-                maxValue = Math.min(max, maxValue);
-
-                if (d > maxValue) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        public intersectsBox(box: BoundingBox): boolean {
-            return this.intersectsBoxMinMax(box.minimum, box.maximum);
-        }
-
-        public intersectsSphere(sphere): boolean {
-            var x = sphere.center.x - this.origin.x;
-            var y = sphere.center.y - this.origin.y;
-            var z = sphere.center.z - this.origin.z;
-            var pyth = (x * x) + (y * y) + (z * z);
-            var rr = sphere.radius * sphere.radius;
-
-            if (pyth <= rr) {
-                return true;
-            }
-
-            var dot = (x * this.direction.x) + (y * this.direction.y) + (z * this.direction.z);
-            if (dot < 0.0) {
-                return false;
-            }
-
-            var temp = pyth - (dot * dot);
-
-            return temp <= rr;
-        }
-
-        public intersectsTriangle(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3): IntersectionInfo {
-            if (!this._edge1) {
-                this._edge1 = Vector3.Zero();
-                this._edge2 = Vector3.Zero();
-                this._pvec = Vector3.Zero();
-                this._tvec = Vector3.Zero();
-                this._qvec = Vector3.Zero();
-            }
-
-            vertex1.subtractToRef(vertex0, this._edge1);
-            vertex2.subtractToRef(vertex0, this._edge2);
-            Vector3.CrossToRef(this.direction, this._edge2, this._pvec);
-            var det = Vector3.Dot(this._edge1, this._pvec);
-
-            if (det === 0) {
-                return null;
-            }
-
-            var invdet = 1 / det;
-
-            this.origin.subtractToRef(vertex0, this._tvec);
-
-            var bu = Vector3.Dot(this._tvec, this._pvec) * invdet;
-
-            if (bu < 0 || bu > 1.0) {
-                return null;
-            }
-
-            Vector3.CrossToRef(this._tvec, this._edge1, this._qvec);
-
-            var bv = Vector3.Dot(this.direction, this._qvec) * invdet;
-
-            if (bv < 0 || bu + bv > 1.0) {
-                return null;
-            }
-
-            //check if the distance is longer than the predefined length.
-            var distance = Vector3.Dot(this._edge2, this._qvec) * invdet;
-            if (distance > this.length) {
-                return null;
-            }
-
-            return new IntersectionInfo(bu, bv, distance);
-        }
-
-        // Statics
-        public static CreateNew(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray {
-            var start = Vector3.Unproject(new Vector3(x, y, 0), viewportWidth, viewportHeight, world, view, projection);
-            var end = Vector3.Unproject(new Vector3(x, y, 1), viewportWidth, viewportHeight, world, view, projection);
-
-            var direction = end.subtract(start);
-            direction.normalize();
-
-            return new Ray(start, direction);
-        }
-
-        /**
-        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
-        * transformed to the given world matrix.
-        * @param origin The origin point
-        * @param end The end point
-        * @param world a matrix to transform the ray to. Default is the identity matrix.
-        */
-        public static CreateNewFromTo(origin: Vector3, end: Vector3, world: Matrix = Matrix.Identity()): Ray {
-            var direction = end.subtract(origin);
-            var length = Math.sqrt((direction.x * direction.x) + (direction.y * direction.y) + (direction.z * direction.z));
-            direction.normalize();
-
-            return Ray.Transform(new Ray(origin, direction, length), world);
-        }
-
-        public static Transform(ray: Ray, matrix: Matrix): Ray {
-            var newOrigin = Vector3.TransformCoordinates(ray.origin, matrix);
-            var newDirection = Vector3.TransformNormal(ray.direction, matrix);
-
-            return new Ray(newOrigin, newDirection, ray.length);
-        }
-    }
-
     export enum Space {
         LOCAL = 0,
         WORLD = 1
@@ -3181,77 +3016,6 @@
         }
     }
 
-    export class PathCursor {
-        private _onchange = new Array<(cursor: PathCursor) => void>();
-
-        value: number = 0;
-        animations = new Array<Animation>();
-
-        constructor(private path: Path2) {
-        }
-
-        public getPoint(): Vector3 {
-            var point = this.path.getPointAtLengthPosition(this.value);
-            return new Vector3(point.x, 0, point.y);
-        }
-
-        public moveAhead(step: number = 0.002): PathCursor {
-            this.move(step);
-
-            return this;
-        }
-
-        public moveBack(step: number = 0.002): PathCursor {
-            this.move(-step);
-
-            return this;
-        }
-
-        public move(step: number): PathCursor {
-
-            if (Math.abs(step) > 1) {
-                throw "step size should be less than 1.";
-            }
-
-            this.value += step;
-            this.ensureLimits();
-            this.raiseOnChange();
-
-            return this;
-        }
-
-        private ensureLimits(): PathCursor {
-            while (this.value > 1) {
-                this.value -= 1;
-            }
-            while (this.value < 0) {
-                this.value += 1;
-            }
-
-            return this;
-        }
-
-        // used by animation engine
-        private markAsDirty(propertyName: string): PathCursor {
-            this.ensureLimits();
-            this.raiseOnChange();
-
-            return this;
-        }
-
-        private raiseOnChange(): PathCursor {
-            this._onchange.forEach(f => f(this));
-
-            return this;
-        }
-
-        public onchange(f: (cursor: PathCursor) => void): PathCursor {
-            this._onchange.push(f);
-
-            return this;
-        }
-    }
-
     export class Path2 {
         private _points = new Array<Vector2>();
         private _length = 0;
@@ -3264,7 +3028,7 @@
 
         public addLineTo(x: number, y: number): Path2 {
             if (closed) {
-                Tools.Error("cannot add lines to closed paths");
+                //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
             var newPoint = new Vector2(x, y);
@@ -3276,7 +3040,7 @@
 
         public addArcTo(midX: number, midY: number, endX: number, endY: number, numberOfSegments = 36): Path2 {
             if (closed) {
-                Tools.Error("cannot add arcs to closed paths");
+                //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }
             var startPoint = this._points[this._points.length - 1];
@@ -3321,7 +3085,7 @@
 
         public getPointAtLengthPosition(normalizedLengthPosition: number): Vector2 {
             if (normalizedLengthPosition < 0 || normalizedLengthPosition > 1) {
-                Tools.Error("normalized length position should be between 0 and 1.");
+                //Tools.Error("normalized length position should be between 0 and 1.");
                 return Vector2.Zero();
             }
 
@@ -3348,7 +3112,7 @@
                 previousOffset = nextOffset;
             }
 
-            Tools.Error("internal error");
+            //Tools.Error("internal error");
             return Vector2.Zero();
         }
 
@@ -3500,13 +3264,13 @@
 
             if (va === undefined || va === null) {
                 var point: Vector3;
-                if (!Tools.WithinEpsilon(vt.y, 1, Engine.Epsilon)) {     // search for a point in the plane
+                if (!MathTools.WithinEpsilon(vt.y, 1, Epsilon)) {     // search for a point in the plane
                     point = new Vector3(0, -1, 0);
                 }
-                else if (!Tools.WithinEpsilon(vt.x, 1, Engine.Epsilon)) {
+                else if (!MathTools.WithinEpsilon(vt.x, 1, Epsilon)) {
                     point = new Vector3(1, 0, 0);
                 }
-                else if (!Tools.WithinEpsilon(vt.z, 1, Engine.Epsilon)) {
+                else if (!MathTools.WithinEpsilon(vt.z, 1, Epsilon)) {
                     point = new Vector3(0, 0, 1);
                 }
                 normal0 = Vector3.Cross(vt, point);
@@ -3715,4 +3479,3 @@
             Matrix.Zero(), Matrix.Zero()];                      // 6 temp Matrices at once should be enough
     }
 }
-

+ 4 - 4
src/Mesh/babylon.abstractMesh.js

@@ -177,7 +177,7 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector. 
-                if (this.rotation.length()) {
+                if (quaternion && this.rotation.length()) {
                     this.rotation.copyFromFloats(0, 0, 0);
                 }
             },
@@ -526,11 +526,11 @@ var BABYLON;
                 }
                 if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
-                        zero.x = localPosition.x + BABYLON.Engine.Epsilon;
+                        zero.x = localPosition.x + BABYLON.Epsilon;
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
-                        zero.y = localPosition.y + 0.001;
+                        zero.y = localPosition.y + BABYLON.Epsilon;
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
-                        zero.z = localPosition.z + 0.001;
+                        zero.z = localPosition.z + BABYLON.Epsilon;
                 }
                 BABYLON.Matrix.LookAtLHToRef(localPosition, zero, BABYLON.Vector3.Up(), BABYLON.Tmp.Matrix[3]);
                 BABYLON.Tmp.Matrix[3].m[12] = BABYLON.Tmp.Matrix[3].m[13] = BABYLON.Tmp.Matrix[3].m[14] = 0;

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

@@ -186,7 +186,7 @@
         public set rotationQuaternion(quaternion: Quaternion) {
             this._rotationQuaternion = quaternion;
             //reset the rotation vector. 
-            if (this.rotation.length()) {
+            if (quaternion && this.rotation.length()) {
                 this.rotation.copyFromFloats(0, 0, 0);
             }
         }
@@ -577,11 +577,11 @@
 
                 if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
-                        zero.x = localPosition.x + Engine.Epsilon;
+                        zero.x = localPosition.x + Epsilon;
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
-                        zero.y = localPosition.y + 0.001;
+                        zero.y = localPosition.y + Epsilon;
                     if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
-                        zero.z = localPosition.z + 0.001;
+                        zero.z = localPosition.z + Epsilon;
                 }
 
                 Matrix.LookAtLHToRef(localPosition, zero, Vector3.Up(), Tmp.Matrix[3]);

+ 2 - 2
src/Mesh/babylon.mesh.js

@@ -47,7 +47,7 @@ var BABYLON;
                     source._geometry.applyToMesh(this);
                 }
                 // Deep copy
-                BABYLON.Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], []);
+                BABYLON.Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], ["_poseMatrix"]);
                 // Pivot                
                 this.setPivotMatrix(source.getPivotMatrix());
                 this.id = name + "." + source.id;
@@ -1245,7 +1245,7 @@ var BABYLON;
                 BABYLON.Node.ParseAnimationRanges(mesh, parsedMesh, scene);
             }
             if (parsedMesh.autoAnimate) {
-                scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, 1.0);
+                scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, parsedMesh.autoAnimateSpeed || 1.0);
             }
             // Layer Mask
             if (parsedMesh.layerMask && (!isNaN(parsedMesh.layerMask))) {

+ 2 - 2
src/Mesh/babylon.mesh.ts

@@ -93,7 +93,7 @@
                 }
 
                 // Deep copy
-                Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], []);
+                Tools.DeepCopy(source, this, ["name", "material", "skeleton", "instances"], ["_poseMatrix"]);
 
                 // Pivot                
                 this.setPivotMatrix(source.getPivotMatrix());
@@ -1472,7 +1472,7 @@
             }
 
             if (parsedMesh.autoAnimate) {
-                scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, 1.0);
+                scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, parsedMesh.autoAnimateSpeed || 1.0);
             }
 
             // Layer Mask

+ 1 - 1
src/Mesh/babylon.meshSimplification.js

@@ -181,7 +181,7 @@ var BABYLON;
             this.syncIterations = 5000;
             this.aggressiveness = 7;
             this.decimationIterations = 100;
-            this.boundingBoxEpsilon = BABYLON.Engine.Epsilon;
+            this.boundingBoxEpsilon = BABYLON.Epsilon;
         }
         QuadraticErrorSimplification.prototype.simplify = function (settings, successCallback) {
             var _this = this;

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

@@ -243,7 +243,7 @@
         constructor(private _mesh: Mesh) {
             this.aggressiveness = 7;
             this.decimationIterations = 100;
-            this.boundingBoxEpsilon = Engine.Epsilon;
+            this.boundingBoxEpsilon = Epsilon;
         }
 
         public simplify(settings: ISimplificationSettings, successCallback: (simplifiedMesh: Mesh) => void) {

+ 3 - 0
src/Particles/babylon.particleSystem.js

@@ -397,6 +397,9 @@ var BABYLON;
                     particleSystem.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                 }
             }
+            if (parsedParticleSystem.autoAnimate) {
+                scene.beginAnimation(particleSystem, parsedParticleSystem.autoAnimateFrom, parsedParticleSystem.autoAnimateTo, parsedParticleSystem.autoAnimateLoop, parsedParticleSystem.autoAnimateSpeed || 1.0);
+            }
             // Particle system
             particleSystem.minAngularSpeed = parsedParticleSystem.minAngularSpeed;
             particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;

+ 4 - 0
src/Particles/babylon.particleSystem.ts

@@ -524,6 +524,10 @@
                 }
             }
 
+            if (parsedParticleSystem.autoAnimate) {
+                scene.beginAnimation(particleSystem, parsedParticleSystem.autoAnimateFrom, parsedParticleSystem.autoAnimateTo, parsedParticleSystem.autoAnimateLoop, parsedParticleSystem.autoAnimateSpeed || 1.0);
+            }
+
             // Particle system
             particleSystem.minAngularSpeed = parsedParticleSystem.minAngularSpeed;
             particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;

+ 52 - 17
src/Physics/Plugins/babylon.cannonJSPlugin.js

@@ -28,8 +28,11 @@ var BABYLON;
         CannonJSPlugin.prototype.setGravity = function (gravity) {
             this.world.gravity.copy(gravity);
         };
+        CannonJSPlugin.prototype.setTimeStep = function (timeStep) {
+            this._fixedTimeStep = timeStep;
+        };
         CannonJSPlugin.prototype.executeStep = function (delta, impostors) {
-            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0, 3);
         };
         CannonJSPlugin.prototype.applyImpulse = function (impostor, force, contactPoint) {
             var worldPoint = new CANNON.Vec3(contactPoint.x, contactPoint.y, contactPoint.z);
@@ -63,7 +66,7 @@ var BABYLON;
                     this.removePhysicsBody(impostor);
                 }
                 //create the body and material
-                var material = this._addMaterial(impostor.getParam("friction"), impostor.getParam("restitution"));
+                var material = this._addMaterial("mat-" + impostor.mesh.uniqueId, impostor.getParam("friction"), impostor.getParam("restitution"));
                 var bodyCreationObject = {
                     mass: impostor.getParam("mass"),
                     material: material
@@ -95,14 +98,14 @@ var BABYLON;
         };
         CannonJSPlugin.prototype._processChildMeshes = function (mainImpostor) {
             var _this = this;
-            var meshChildren = mainImpostor.mesh.getChildMeshes(true);
+            var meshChildren = mainImpostor.mesh.getChildMeshes();
             if (meshChildren.length) {
-                var processMesh = function (relativePosition, mesh) {
+                var processMesh = function (localPosition, mesh) {
                     var childImpostor = mesh.getPhysicsImpostor();
                     if (childImpostor) {
                         var parent = childImpostor.parent;
                         if (parent !== mainImpostor) {
-                            var localPosition = mesh.position.add(relativePosition);
+                            var localPosition = mesh.position;
                             if (childImpostor.physicsBody) {
                                 _this.removePhysicsBody(childImpostor);
                                 childImpostor.physicsBody = null;
@@ -114,7 +117,7 @@ var BABYLON;
                             mainImpostor.physicsBody.mass += childImpostor.getParam("mass");
                         }
                     }
-                    mesh.getChildMeshes(true).forEach(processMesh.bind(_this, mesh.position));
+                    mesh.getChildMeshes().forEach(processMesh.bind(_this, mesh.position));
                 };
                 meshChildren.forEach(processMesh.bind(this, BABYLON.Vector3.Zero()));
             }
@@ -139,9 +142,11 @@ var BABYLON;
                 pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
                 axisA: jointData.mainAxis ? new CANNON.Vec3().copy(jointData.mainAxis) : null,
                 axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
-                maxForce: jointData.nativeParams.maxForce
+                maxForce: jointData.nativeParams.maxForce,
+                collideConnected: !!jointData.collision
             };
-            if (!jointData.collision) {
+            //Not needed, Cannon has a collideConnected flag
+            /*if (!jointData.collision) {
                 //add 1st body to a collision group of its own, if it is not in 1
                 if (mainBody.collisionFilterGroup === 1) {
                     mainBody.collisionFilterGroup = this._currentCollisionGroup;
@@ -154,7 +159,7 @@ var BABYLON;
                 //add their mask to the collisionFilterMask of each other:
                 connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
                 mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
-            }
+            }*/
             switch (impostorJoint.joint.type) {
                 case BABYLON.PhysicsJoint.HingeJoint:
                     constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
@@ -162,17 +167,37 @@ var BABYLON;
                 case BABYLON.PhysicsJoint.DistanceJoint:
                     constraint = new CANNON.DistanceConstraint(mainBody, connectedBody, jointData.maxDistance || 2);
                     break;
+                case BABYLON.PhysicsJoint.SpringJoint:
+                    var springData = jointData;
+                    constraint = new CANNON.Spring(mainBody, connectedBody, {
+                        restLength: springData.length,
+                        stiffness: springData.stiffness,
+                        damping: springData.damping,
+                        localAnchorA: constraintData.pivotA,
+                        localAnchorB: constraintData.pivotB
+                    });
+                    break;
                 default:
                     constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
                     break;
             }
+            //set the collideConnected flag after the creation, since DistanceJoint ignores it.
+            constraint.collideConnected = !!jointData.collision;
             impostorJoint.joint.physicsJoint = constraint;
-            this.world.addConstraint(constraint);
+            //don't add spring as constraint, as it is not one.
+            if (impostorJoint.joint.type !== BABYLON.PhysicsJoint.SpringJoint) {
+                this.world.addConstraint(constraint);
+            }
+            else {
+                impostorJoint.mainImpostor.registerAfterPhysicsStep(function () {
+                    constraint.applyForce();
+                });
+            }
         };
         CannonJSPlugin.prototype.removeJoint = function (joint) {
             //TODO
         };
-        CannonJSPlugin.prototype._addMaterial = function (friction, restitution) {
+        CannonJSPlugin.prototype._addMaterial = function (name, friction, restitution) {
             var index;
             var mat;
             for (index = 0; index < this._physicsMaterials.length; index++) {
@@ -182,12 +207,9 @@ var BABYLON;
                 }
             }
             var currentMat = new CANNON.Material("mat");
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
             this._physicsMaterials.push(currentMat);
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
-                this.world.addContactMaterial(contactMaterial);
-            }
             return currentMat;
         };
         CannonJSPlugin.prototype._checkWithEpsilon = function (value) {
@@ -343,9 +365,22 @@ var BABYLON;
         CannonJSPlugin.prototype.isSupported = function () {
             return window.CANNON !== undefined;
         };
-        CannonJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+        CannonJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
             impostor.physicsBody.velocity.copy(velocity);
         };
+        CannonJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
+            impostor.physicsBody.angularVelocity.copy(velocity);
+        };
+        CannonJSPlugin.prototype.setBodyMass = function (impostor, mass) {
+            impostor.physicsBody.mass = mass;
+            impostor.physicsBody.updateMassProperties();
+        };
+        CannonJSPlugin.prototype.sleepBody = function (impostor) {
+            impostor.physicsBody.sleep();
+        };
+        CannonJSPlugin.prototype.wakeUpBody = function (impostor) {
+            impostor.physicsBody.wakeUp();
+        };
         CannonJSPlugin.prototype.dispose = function () {
             //nothing to do, actually.
         };

+ 59 - 22
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -24,8 +24,12 @@
             this.world.gravity.copy(gravity);
         }
 
+        public setTimeStep(timeStep: number) {
+            this._fixedTimeStep = timeStep;
+        }
+
         public executeStep(delta: number, impostors: Array<PhysicsImpostor>): void {
-            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0);
+            this.world.step(this._fixedTimeStep, this._useDeltaForWorldStep ? delta * 1000 : 0, 3);
         }
 
         public applyImpulse(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
@@ -68,7 +72,7 @@
                 }
                 
                 //create the body and material
-                var material = this._addMaterial(impostor.getParam("friction"), impostor.getParam("restitution"));
+                var material = this._addMaterial("mat-" + impostor.mesh.uniqueId, impostor.getParam("friction"), impostor.getParam("restitution"));
 
                 var bodyCreationObject = {
                     mass: impostor.getParam("mass"),
@@ -103,14 +107,14 @@
         }
 
         private _processChildMeshes(mainImpostor: PhysicsImpostor) {
-            var meshChildren = mainImpostor.mesh.getChildMeshes(true);
+            var meshChildren = mainImpostor.mesh.getChildMeshes();
             if (meshChildren.length) {
-                var processMesh = (relativePosition: Vector3, mesh: AbstractMesh) => {
+                var processMesh = (localPosition: Vector3, mesh: AbstractMesh) => {
                     var childImpostor = mesh.getPhysicsImpostor();
                     if (childImpostor) {
                         var parent = childImpostor.parent;
                         if (parent !== mainImpostor) {
-                            var localPosition = mesh.position.add(relativePosition);
+                            var localPosition = mesh.position;
                             if (childImpostor.physicsBody) {
                                 this.removePhysicsBody(childImpostor);
                                 childImpostor.physicsBody = null;
@@ -122,7 +126,7 @@
                             mainImpostor.physicsBody.mass += childImpostor.getParam("mass");
                         }
                     }
-                    mesh.getChildMeshes(true).forEach(processMesh.bind(this, mesh.position));
+                    mesh.getChildMeshes().forEach(processMesh.bind(this, mesh.position));
                 }
                 meshChildren.forEach(processMesh.bind(this, Vector3.Zero()));
             }
@@ -149,9 +153,11 @@
                 pivotB: jointData.connectedPivot ? new CANNON.Vec3().copy(jointData.connectedPivot) : null,
                 axisA: jointData.mainAxis ? new CANNON.Vec3().copy(jointData.mainAxis) : null,
                 axisB: jointData.connectedAxis ? new CANNON.Vec3().copy(jointData.connectedAxis) : null,
-                maxForce: jointData.nativeParams.maxForce
+                maxForce: jointData.nativeParams.maxForce,
+                collideConnected: !!jointData.collision
             };
-            if (!jointData.collision) {
+            //Not needed, Cannon has a collideConnected flag
+            /*if (!jointData.collision) {
                 //add 1st body to a collision group of its own, if it is not in 1
                 if (mainBody.collisionFilterGroup === 1) {
                     mainBody.collisionFilterGroup = this._currentCollisionGroup;
@@ -164,7 +170,7 @@
                 //add their mask to the collisionFilterMask of each other:
                 connectedBody.collisionFilterMask = connectedBody.collisionFilterMask | ~mainBody.collisionFilterGroup;
                 mainBody.collisionFilterMask = mainBody.collisionFilterMask | ~connectedBody.collisionFilterGroup;
-            }
+            }*/
             switch (impostorJoint.joint.type) {
                 case PhysicsJoint.HingeJoint:
                     constraint = new CANNON.HingeConstraint(mainBody, connectedBody, constraintData);
@@ -172,19 +178,38 @@
                 case PhysicsJoint.DistanceJoint:
                     constraint = new CANNON.DistanceConstraint(mainBody, connectedBody, (<DistanceJointData>jointData).maxDistance || 2)
                     break;
+                case PhysicsJoint.SpringJoint:
+                    var springData = <SpringJointData>jointData;
+                    constraint = new CANNON.Spring(mainBody, connectedBody, {
+                        restLength: springData.length,
+                        stiffness: springData.stiffness,
+                        damping: springData.damping,
+                        localAnchorA: constraintData.pivotA,
+                        localAnchorB: constraintData.pivotB
+                    });
+                    break;
                 default:
                     constraint = new CANNON.PointToPointConstraint(mainBody, constraintData.pivotA, connectedBody, constraintData.pivotA, constraintData.maxForce);
                     break;
             }
+            //set the collideConnected flag after the creation, since DistanceJoint ignores it.
+            constraint.collideConnected = !!jointData.collision
             impostorJoint.joint.physicsJoint = constraint;
-            this.world.addConstraint(constraint);
+            //don't add spring as constraint, as it is not one.
+            if (impostorJoint.joint.type !== PhysicsJoint.SpringJoint) {
+                this.world.addConstraint(constraint);
+            } else {
+                impostorJoint.mainImpostor.registerAfterPhysicsStep(function () {
+                    constraint.applyForce();
+                });
+            }
         }
 
         public removeJoint(joint: PhysicsImpostorJoint) {
             //TODO
         }
 
-        private _addMaterial(friction: number, restitution: number) {
+        private _addMaterial(name: string, friction: number, restitution: number) {
             var index;
             var mat;
 
@@ -197,16 +222,10 @@
             }
 
             var currentMat = new CANNON.Material("mat");
-            this._physicsMaterials.push(currentMat);
-
-            for (index = 0; index < this._physicsMaterials.length; index++) {
-                mat = this._physicsMaterials[index];
-
-                var contactMaterial = new CANNON.ContactMaterial(mat, currentMat, { friction: friction, restitution: restitution });
-
-                this.world.addContactMaterial(contactMaterial);
-            }
+            currentMat.friction = friction;
+            currentMat.restitution = restitution;
 
+            this._physicsMaterials.push(currentMat);
             return currentMat;
         }
 
@@ -408,12 +427,30 @@
             return window.CANNON !== undefined;
         }
 
-        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+        public setLinearVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
             impostor.physicsBody.velocity.copy(velocity);
         }
 
+        public setAngularVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.angularVelocity.copy(velocity);
+        }
+
+        public setBodyMass(impostor: PhysicsImpostor, mass: number) {
+            impostor.physicsBody.mass = mass;
+            impostor.physicsBody.updateMassProperties();
+        }
+
+        public sleepBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.sleep();
+        }
+
+        public wakeUpBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.wakeUp();
+        }
+
         public dispose() {
             //nothing to do, actually.
         }
     }
-}
+}
+

+ 26 - 1
src/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -13,6 +13,9 @@ var BABYLON;
         OimoJSPlugin.prototype.setGravity = function (gravity) {
             this.world.gravity.copy(gravity);
         };
+        OimoJSPlugin.prototype.setTimeStep = function (timeStep) {
+            this.world.timeStep = timeStep;
+        };
         OimoJSPlugin.prototype.executeStep = function (delta, impostors) {
             var _this = this;
             impostors.forEach(function (impostor) {
@@ -193,6 +196,12 @@ var BABYLON;
                 case BABYLON.PhysicsJoint.BallAndSocketJoint:
                     type = "jointBall";
                     break;
+                case BABYLON.PhysicsJoint.SpringJoint:
+                    BABYLON.Tools.Warn("Oimo.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
+                    var springData = jointData;
+                    nativeJointData.min = springData.length || nativeJointData.min;
+                    //Max should also be set, just make sure it is at least min
+                    nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
                 case BABYLON.PhysicsJoint.DistanceJoint:
                     type = "jointDistance";
                     nativeJointData.max = jointData.maxDistance;
@@ -249,9 +258,25 @@ var BABYLON;
             }
             return lastShape;
         };
-        OimoJSPlugin.prototype.setVelocity = function (impostor, velocity) {
+        OimoJSPlugin.prototype.setLinearVelocity = function (impostor, velocity) {
             impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
         };
+        OimoJSPlugin.prototype.setAngularVelocity = function (impostor, velocity) {
+            impostor.physicsBody.angularVelocity.init(velocity.x, velocity.y, velocity.z);
+        };
+        OimoJSPlugin.prototype.setBodyMass = function (impostor, mass) {
+            var staticBody = mass === 0;
+            //this will actually set the body's density and not its mass.
+            //But this is how oimo treats the mass variable.
+            impostor.physicsBody.shapes.density = staticBody ? 1 : mass;
+            impostor.physicsBody.setupMass(staticBody ? 0x2 : 0x1);
+        };
+        OimoJSPlugin.prototype.sleepBody = function (impostor) {
+            impostor.physicsBody.sleep();
+        };
+        OimoJSPlugin.prototype.wakeUpBody = function (impostor) {
+            impostor.physicsBody.awake();
+        };
         OimoJSPlugin.prototype.dispose = function () {
             this.world.clear();
         };

+ 33 - 2
src/Physics/Plugins/babylon.oimoJSPlugin.ts

@@ -17,6 +17,10 @@ module BABYLON {
             this.world.gravity.copy(gravity);
         }
 
+        public setTimeStep(timeStep: number) {
+            this.world.timeStep = timeStep;
+        }
+
         private _tmpImpostorsArray: Array<PhysicsImpostor> = [];
 
         public executeStep(delta: number, impostors: Array<PhysicsImpostor>) {
@@ -242,6 +246,12 @@ module BABYLON {
                 case PhysicsJoint.BallAndSocketJoint:
                     type = "jointBall";
                     break;
+                case PhysicsJoint.SpringJoint:
+                    Tools.Warn("Oimo.js doesn't support Spring Constraint. Simulating using DistanceJoint instead");
+                    var springData = <SpringJointData>jointData;
+                    nativeJointData.min = springData.length || nativeJointData.min;
+                    //Max should also be set, just make sure it is at least min
+                    nativeJointData.max = Math.max(nativeJointData.min, nativeJointData.max);
                 case PhysicsJoint.DistanceJoint:
                     type = "jointDistance";
                     nativeJointData.max = (<DistanceJointData>jointData).maxDistance
@@ -306,12 +316,33 @@ module BABYLON {
             return lastShape;
         }
 
-        public setVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+        public setLinearVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
             impostor.physicsBody.linearVelocity.init(velocity.x, velocity.y, velocity.z);
         }
 
+        public setAngularVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
+            impostor.physicsBody.angularVelocity.init(velocity.x, velocity.y, velocity.z);
+        }
+
+
+        public setBodyMass(impostor: PhysicsImpostor, mass: number) {
+            var staticBody: boolean = mass === 0;
+            //this will actually set the body's density and not its mass.
+            //But this is how oimo treats the mass variable.
+            impostor.physicsBody.shapes.density = staticBody ? 1 : mass;
+            impostor.physicsBody.setupMass(staticBody ? 0x2 : 0x1);
+        }
+
+        public sleepBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.sleep();
+        }
+
+        public wakeUpBody(impostor: PhysicsImpostor) {
+            impostor.physicsBody.awake();
+        }
+
         public dispose() {
             this.world.clear();
         }
     }
-}
+}

+ 0 - 0
src/Physics/babylon.physicsEngine.js


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä