Преглед изворни кода

Fixing json generation for 3ds max exporter
Adding new paramater to executecodeaction to define which object has raised the action

David Catuhe пре 11 година
родитељ
комит
29036ac228

+ 3 - 3
Babylon/Actions/babylon.action.js

@@ -10,7 +10,7 @@
         Action.prototype._prepare = function () {
         };
 
-        Action.prototype._executeCurrent = function () {
+        Action.prototype._executeCurrent = function (source) {
             if (this._condition) {
                 var currentRenderId = this._actionManager.getScene().getRenderId();
 
@@ -31,7 +31,7 @@
                 }
             }
 
-            this._nextActiveAction.execute();
+            this._nextActiveAction.execute(source);
 
             if (this._nextActiveAction._child) {
                 this._nextActiveAction = this._nextActiveAction._child;
@@ -40,7 +40,7 @@
             }
         };
 
-        Action.prototype.execute = function () {
+        Action.prototype.execute = function (source) {
         };
 
         Action.prototype.then = function (action) {

+ 5 - 5
Babylon/Actions/babylon.action.ts

@@ -2,8 +2,8 @@
     export class Action {
         public _actionManager: ActionManager;
 
-        private _nextActiveAction;
-        private _child;
+        private _nextActiveAction: Action;
+        private _child: Action;
         private _condition: Condition;
 
         constructor(public trigger: number, condition?: Condition) {
@@ -15,7 +15,7 @@
         public _prepare(): void {
         }
 
-        public _executeCurrent(): void {
+        public _executeCurrent(source: AbstractMesh): void {
             if (this._condition) {
                 var currentRenderId = this._actionManager.getScene().getRenderId();
 
@@ -36,7 +36,7 @@
                 }
             }
 
-            this._nextActiveAction.execute();
+            this._nextActiveAction.execute(source);
 
             if (this._nextActiveAction._child) {
                 this._nextActiveAction = this._nextActiveAction._child;
@@ -45,7 +45,7 @@
             }
         }
 
-        public execute(): void {
+        public execute(source: AbstractMesh): void {
 
         }
 

+ 2 - 2
Babylon/Actions/babylon.actionManager.js

@@ -91,12 +91,12 @@
             return action;
         };
 
-        ActionManager.prototype.processTrigger = function (trigger) {
+        ActionManager.prototype.processTrigger = function (trigger, source) {
             for (var index = 0; index < this.actions.length; index++) {
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    action._executeCurrent();
+                    action._executeCurrent(source);
                 }
             }
         };

+ 2 - 2
Babylon/Actions/babylon.actionManager.ts

@@ -73,12 +73,12 @@
             return action;
         }
 
-        public processTrigger(trigger: number): void {
+        public processTrigger(trigger: number, source: AbstractMesh): void {
             for (var index = 0; index < this.actions.length; index++) {
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    action._executeCurrent();
+                    action._executeCurrent(source);
                 }
             }
         }

+ 4 - 4
Babylon/Actions/babylon.directActions.js

@@ -145,9 +145,9 @@ var BABYLON;
             }
         };
 
-        CombineAction.prototype.execute = function () {
+        CombineAction.prototype.execute = function (source) {
             for (var index = 0; index < this.children.length; index++) {
-                this.children[index].execute();
+                this.children[index].execute(source);
             }
         };
         return CombineAction;
@@ -160,8 +160,8 @@ var BABYLON;
             _super.call(this, trigger, condition);
             this.func = func;
         }
-        ExecuteCodeAction.prototype.execute = function () {
-            this.func();
+        ExecuteCodeAction.prototype.execute = function (source) {
+            this.func(source);
         };
         return ExecuteCodeAction;
     })(BABYLON.Action);

+ 5 - 5
Babylon/Actions/babylon.directActions.ts

@@ -128,20 +128,20 @@
             }
         }
 
-        public execute(): void {
+        public execute(source: AbstractMesh): void {
             for (var index = 0; index < this.children.length; index++) {
-                this.children[index].execute();
+                this.children[index].execute(source);
             }
         }
     }
 
     export class ExecuteCodeAction extends Action {
-        constructor(trigger: number, public func: () => void, condition?: Condition) {
+        constructor(trigger: number, public func: (source: AbstractMesh) => void, condition?: Condition) {
             super(trigger, condition);
         }
 
-        public execute(): void {
-            this.func();
+        public execute(source: AbstractMesh): void {
+            this.func(source);
         }
     }
 

+ 2 - 2
Babylon/Collisions/babylon.pickingInfo.ts

@@ -9,8 +9,8 @@
     export class PickingInfo {
         public hit = false;
         public distance = 0;
-        public pickedPoint = null;
-        public pickedMesh = null;
+        public pickedPoint: Vector3 = null;
+        public pickedMesh: AbstractMesh = null;
         public bu = 0;
         public bv = 0;
         public faceId = -1;

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

@@ -156,4 +156,4 @@
     })();
     BABYLON.BoundingBox = BoundingBox;
 })(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.BoundingBox.js.map
+//# sourceMappingURL=babylon.boundingBox.js.map

+ 2 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -523,6 +523,8 @@ var BABYLON = BABYLON || {};
 
         if (parsedMesh.localMatrix) {
             mesh.setPivotMatrix(BABYLON.Matrix.FromArray(parsedMesh.localMatrix));
+        } else if (parsedMesh.pivotMatrix) {
+            mesh.setPivotMatrix(BABYLON.Matrix.FromArray(parsedMesh.pivotMatrix));
         }
 
         mesh.setEnabled(parsedMesh.isEnabled);

+ 8 - 8
Babylon/babylon.scene.js

@@ -203,16 +203,16 @@
                     if (pickResult.pickedMesh.actionManager) {
                         switch (evt.buttons) {
                             case 1:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, pickResult.pickedMesh);
                                 break;
                             case 2:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, pickResult.pickedMesh);
                                 break;
                             case 3:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, pickResult.pickedMesh);
                                 break;
                         }
-                        pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger);
+                        pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, pickResult.pickedMesh);
                     }
                 }
 
@@ -774,7 +774,7 @@
             var beforeRenderTargetDate = new Date().getTime();
             if (this.renderTargetsEnabled) {
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
-                    var renderTarget = this._renderTargets.data[renderIndex];
+                    renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
                         this._renderId++;
                         renderTarget.render();
@@ -874,7 +874,7 @@
 
             // Actions
             if (this.actionManager) {
-                this.actionManager.processTrigger(BABYLON.ActionManager.OnEveryFrameTrigger);
+                this.actionManager.processTrigger(BABYLON.ActionManager.OnEveryFrameTrigger, null);
             }
 
             // Before render
@@ -1162,12 +1162,12 @@
             }
 
             if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
-                this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger);
+                this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOutTrigger, this._pointerOverMesh);
             }
 
             this._pointerOverMesh = mesh;
             if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
-                this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger);
+                this._pointerOverMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPointerOverTrigger, this._pointerOverMesh);
             }
         };
 

+ 11 - 11
Babylon/babylon.scene.ts

@@ -149,7 +149,7 @@
 
         private _selectionOctree: Octree<AbstractMesh>;
 
-        private _pointerOverMesh: Mesh;
+        private _pointerOverMesh: AbstractMesh;
 
         // Constructor
         constructor(engine: Engine) {
@@ -266,16 +266,16 @@
                     if (pickResult.pickedMesh.actionManager) {
                         switch (evt.buttons) {
                             case 1:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnLeftPickTrigger, pickResult.pickedMesh);
                                 break;
                             case 2:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnRightPickTrigger, pickResult.pickedMesh);
                                 break;
                             case 3:
-                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger);
+                                pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnCenterPickTrigger, pickResult.pickedMesh);
                                 break;
                         }
-                        pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger);
+                        pickResult.pickedMesh.actionManager.processTrigger(BABYLON.ActionManager.OnPickTrigger, pickResult.pickedMesh);
                     }
                 }
 
@@ -838,7 +838,7 @@
             var beforeRenderTargetDate = new Date().getTime();
             if (this.renderTargetsEnabled) {
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
-                    var renderTarget = this._renderTargets.data[renderIndex];
+                    renderTarget = this._renderTargets.data[renderIndex];
                     if (renderTarget._shouldRender()) {
                         this._renderId++;
                         renderTarget.render();
@@ -940,7 +940,7 @@
 
             // Actions
             if (this.actionManager) {
-                this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger);
+                this.actionManager.processTrigger(ActionManager.OnEveryFrameTrigger, null);
             }
 
             // Before render
@@ -1227,22 +1227,22 @@
             }, predicate, fastCheck);
         }
 
-        public setPointerOverMesh(mesh: Mesh): void {
+        public setPointerOverMesh(mesh: AbstractMesh): void {
             if (this._pointerOverMesh === mesh) {
                 return;
             }
 
             if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
-                this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOutTrigger);
+                this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOutTrigger, this._pointerOverMesh);
             }
 
             this._pointerOverMesh = mesh;
             if (this._pointerOverMesh && this._pointerOverMesh.actionManager) {
-                this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOverTrigger);
+                this._pointerOverMesh.actionManager.processTrigger(ActionManager.OnPointerOverTrigger, this._pointerOverMesh);
             }
         }
 
-        public getPointerOverMesh(): Mesh {
+        public getPointerOverMesh(): AbstractMesh {
             return this._pointerOverMesh;
         }
 

+ 1 - 1
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -39,7 +39,7 @@ namespace BabylonExport.Entities
         public float[] rotationQuaternion { get; set; }
 
         [DataMember]
-        public float[] localMatrix { get; set; }
+        public float[] pivotMatrix { get; set; }
 
         [DataMember]
         public float[] positions { get; set; }

+ 1 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs

@@ -48,6 +48,7 @@ namespace Max2Babylon
                 babylonMultimaterial.materials = guids.ToArray();
 
                 babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
+                return;
             }
 
 

+ 32 - 19
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -74,11 +74,11 @@ namespace Max2Babylon
             }
 
             // Pivot
-            //var pivotMatrix = Matrix3.Identity._IMatrix3;
-            //pivotMatrix.PreTranslate(meshNode._Node.ObjOffsetPos);
-            //Loader.Global.PreRotateMatrix(pivotMatrix, meshNode._Node.ObjOffsetRot);
-            //Loader.Global.ApplyScaling(pivotMatrix, meshNode._Node.ObjOffsetScale);
-            //babylonMesh.localMatrix = pivotMatrix.ToArray();
+            var pivotMatrix = Matrix3.Identity._IMatrix3;
+            pivotMatrix.PreTranslate(meshNode._Node.ObjOffsetPos);
+            Loader.Global.PreRotateMatrix(pivotMatrix, meshNode._Node.ObjOffsetRot);
+            Loader.Global.ApplyScaling(pivotMatrix, meshNode._Node.ObjOffsetScale);
+            babylonMesh.pivotMatrix = pivotMatrix.ToArray();
 
             // Mesh
             var objectState = meshNode._Node.EvalWorldState(0, false);
@@ -129,14 +129,21 @@ namespace Max2Babylon
                 var hasUV = mesh.NumTVerts > 0;
                 var hasUV2 = mesh.GetNumMapVerts(2) > 0;
 
+                var noOptimize = meshNode._Node.GetBoolProperty("babylonjs_nooptimize");
+                
                 for (var face = 0; face < mesh.NumFaces; face++)
                 {
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2));
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2));
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2, noOptimize));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2, noOptimize));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2, noOptimize));
                     matIDs.Add(mesh.Faces[face].MatID % multiMatsCount);
                 }
 
+                if (vertices.Count >= 65536)
+                {
+                    RaiseError(string.Format("Mesh {0} has too many vertices: {1} (limit is 65535)", babylonMesh.name, vertices.Count));
+                }
+
                 // Buffers
                 babylonMesh.positions = vertices.SelectMany(v => v.Position.ToArraySwitched()).ToArray();
                 babylonMesh.normals = vertices.SelectMany(v => v.Normal.ToArraySwitched()).ToArray();
@@ -207,13 +214,17 @@ namespace Max2Babylon
                             }
                         }
                     }
-                    subMesh.indexCount = indexCount;
-                    subMesh.verticesStart = minVertexIndex;
-                    subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;
+                    if (indexCount != 0)
+                    {
+
+                        subMesh.indexCount = indexCount;
+                        subMesh.verticesStart = minVertexIndex;
+                        subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;
 
-                    indexStart += indexCount;
+                        indexStart += indexCount;
 
-                    subMeshes.Add(subMesh);
+                        subMeshes.Add(subMesh);
+                    }
                 }
                 babylonMesh.subMeshes = subMeshes.ToArray();
 
@@ -227,7 +238,7 @@ namespace Max2Babylon
             return babylonMesh;
         }
 
-        int CreateGlobalVertex(IMesh mesh, Mesh computedMesh, int face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2)
+        int CreateGlobalVertex(IMesh mesh, Mesh computedMesh, int face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool noOptimize)
         {
             var vertexIndex = (int)mesh.Faces[face].V[facePart];
 
@@ -250,12 +261,14 @@ namespace Max2Babylon
                 vertex.UV2 = Loader.Global.Point2.Create(mesh.MapVerts(2)[tvertexIndex].X, mesh.MapVerts(2)[tvertexIndex].Y);
             }
 
-
-            var index = vertices.IndexOf(vertex);
-
-            if (index > -1)
+            if (!noOptimize)
             {
-                return index;
+                var index = vertices.IndexOf(vertex);
+
+                if (index > -1)
+                {
+                    return index;
+                }
             }
 
             vertices.Add(vertex);

+ 13 - 5
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs

@@ -1,11 +1,14 @@
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.Runtime.InteropServices;
 using System.Runtime.Serialization.Json;
+using System.Text;
 using Autodesk.Max;
 using BabylonExport.Entities;
 using MaxSharp;
+using Newtonsoft.Json;
 using Animatable = MaxSharp.Animatable;
 
 namespace Max2Babylon
@@ -27,7 +30,7 @@ namespace Max2Babylon
             }
         }
 
-        void RaiseError(string error, bool asChild = false)
+        void RaiseError(string error, bool asChild = true)
         {
             if (OnError != null)
             {
@@ -141,14 +144,19 @@ namespace Max2Babylon
 
             // Output
             babylonScene.Prepare(false);
-            using (var outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
+            var jsonSerializer = JsonSerializer.Create();
+            var sb = new StringBuilder();
+            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+            using (var jsonWriter = new JsonTextWriterOptimized(sw))
             {
-                var ser = new DataContractJsonSerializer(typeof(BabylonScene));
-                ser.WriteObject(outputStream, babylonScene);
+                jsonWriter.Formatting = Formatting.None;
+                jsonSerializer.Serialize(jsonWriter, babylonScene);
             }
+            File.WriteAllText(outputFile, sb.ToString());
+
             ReportProgressChanged(100);
 
             RaiseMessage("Exportation done");
-        }             
+        }
     }
 }

+ 15 - 1
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs

@@ -34,6 +34,7 @@
             this.butOK = new System.Windows.Forms.Button();
             this.groupBox2 = new System.Windows.Forms.GroupBox();
             this.chkPickable = new System.Windows.Forms.CheckBox();
+            this.chkNoOptimize = new System.Windows.Forms.CheckBox();
             this.groupBox1.SuspendLayout();
             this.groupBox2.SuspendLayout();
             this.SuspendLayout();
@@ -87,11 +88,12 @@
             // 
             // groupBox2
             // 
+            this.groupBox2.Controls.Add(this.chkNoOptimize);
             this.groupBox2.Controls.Add(this.chkPickable);
             this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.groupBox2.Location = new System.Drawing.Point(12, 77);
             this.groupBox2.Name = "groupBox2";
-            this.groupBox2.Size = new System.Drawing.Size(319, 59);
+            this.groupBox2.Size = new System.Drawing.Size(319, 113);
             this.groupBox2.TabIndex = 2;
             this.groupBox2.TabStop = false;
             this.groupBox2.Text = "Misc.";
@@ -107,6 +109,17 @@
             this.chkPickable.ThreeState = true;
             this.chkPickable.UseVisualStyleBackColor = true;
             // 
+            // chkNoOptimize
+            // 
+            this.chkNoOptimize.AutoSize = true;
+            this.chkNoOptimize.Location = new System.Drawing.Point(21, 51);
+            this.chkNoOptimize.Name = "chkNoOptimize";
+            this.chkNoOptimize.Size = new System.Drawing.Size(165, 17);
+            this.chkNoOptimize.TabIndex = 1;
+            this.chkNoOptimize.Text = "Do not try to optimize vertices";
+            this.chkNoOptimize.ThreeState = true;
+            this.chkNoOptimize.UseVisualStyleBackColor = true;
+            // 
             // ObjectPropertiesForm
             // 
             this.AcceptButton = this.butOK;
@@ -139,5 +152,6 @@
         private System.Windows.Forms.Button butOK;
         private System.Windows.Forms.GroupBox groupBox2;
         private System.Windows.Forms.CheckBox chkPickable;
+        private System.Windows.Forms.CheckBox chkNoOptimize;
     }
 }

+ 3 - 1
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs

@@ -17,7 +17,8 @@ namespace Max2Babylon
         private void butOK_Click(object sender, EventArgs e)
         {
             Tools.UpdateCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
-            Tools.UpdateCheckBox(chkPickable, objects, "babylonjs_checkpickable");            
+            Tools.UpdateCheckBox(chkPickable, objects, "babylonjs_checkpickable");   
+            Tools.UpdateCheckBox(chkNoOptimize, objects, "babylonjs_nooptimize");
         }
 
         private void ObjectPropertiesForm_Load(object sender, EventArgs e)
@@ -34,6 +35,7 @@ namespace Max2Babylon
 
             Tools.PrepareCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
             Tools.PrepareCheckBox(chkPickable, objects, "babylonjs_checkpickable");
+            Tools.PrepareCheckBox(chkNoOptimize, objects, "babylonjs_nooptimize");
         }
     }
 }

+ 19 - 0
Exporters/3ds Max/Max2Babylon/JsonTextWriterOptimized.cs

@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace Max2Babylon
+{
+    class JsonTextWriterOptimized : JsonTextWriter
+    {
+        public JsonTextWriterOptimized(TextWriter textWriter)
+            : base(textWriter)
+        {
+        }
+        public override void WriteValue(float value)
+        {
+            value = (float)Math.Round(value, 4);
+            base.WriteValue(value);
+        }
+    }
+}

+ 22 - 0
Exporters/3ds Max/Max2Babylon/Tools.cs

@@ -5,11 +5,33 @@ using System.Windows.Forms;
 using Autodesk.Max;
 using Autodesk.Max.IMXSDebugger;
 using MaxSharp;
+using SharpDX;
+using Color = MaxSharp.Color;
 
 namespace Max2Babylon
 {
     public static class Tools
     {
+        public static float[] ToArray(this IMatrix3 value)
+        {
+            var row0 = value.GetRow(0).ToArraySwitched();
+            var row1 = value.GetRow(1).ToArraySwitched();
+            var row2 = value.GetRow(2).ToArraySwitched();
+            var row3 = value.GetRow(3).ToArraySwitched();
+
+            return new[]
+            {
+                row0[0], row0[1], row0[2], 0,
+                row2[0], row2[1], row2[2], 0,
+                row1[0], row1[1], row1[2], 0,
+                row3[0], row3[1], row3[2], 1
+            };
+        }
+
+        public static Quaternion ToQuat(this IQuat value)
+        {
+            return new Quaternion(value.X, value.Z, value.Y, value.W );
+        }
         public static float[] ToArray(this IQuat value)
         {
             return new[] { value.X, value.Z, value.Y, value.W };

Разлика између датотеке није приказан због своје велике величине
+ 12 - 12
babylon.1.12-beta.js