コード例 #1
0
ファイル: BabylonExporter.cs プロジェクト: thr0wn/Babylon.js
        public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, Form callerForm)
        {
            var gameConversionManger = Loader.Global.ConversionManager;
            gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d;

            var gameScene = Loader.Global.IGameInterface;
            gameScene.InitialiseIGame(onlySelected);
            gameScene.SetStaticFrame(0);

            MaxSceneFileName = gameScene.SceneFileName;

            IsCancelled = false;
            RaiseMessage("Exportation started", Color.Blue);
            ReportProgressChanged(0);
            var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile));
            var rawScene = Loader.Core.RootNode;

            if (!Directory.Exists(babylonScene.OutputPath))
            {
                RaiseError("Exportation stopped: Output folder does not exist");
                ReportProgressChanged(100);
                return;
            }

            var watch = new Stopwatch();
            watch.Start();

            // Save scene
            RaiseMessage("Saving 3ds max file");

            if (AutoSave3dsMaxFile)
            {
                var forceSave = Loader.Core.FileSave;

                if (callerForm != null)
                {
                    callerForm.BringToFront();
                }
            }

            // Global
            babylonScene.autoClear = true;
            babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray();
            babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray();

            babylonScene.gravity = rawScene.GetVector3Property("babylonjs_gravity");
            ExportQuaternionsInsteadOfEulers = rawScene.GetBoolProperty("babylonjs_exportquaternions", 1);

            // Sounds
            var soundName = rawScene.GetStringProperty("babylonjs_sound_filename", "");

            if (!string.IsNullOrEmpty(soundName))
            {
                var filename = Path.GetFileName(soundName);

                var globalSound = new BabylonSound
                {
                    autoplay = rawScene.GetBoolProperty("babylonjs_sound_autoplay", 1),
                    loop = rawScene.GetBoolProperty("babylonjs_sound_loop", 1),
                    name = filename
                };

                babylonScene.SoundsList.Add(globalSound);

                try
                {
                    File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true);
                }
                catch
                {
                }
            }

            // Cameras
            BabylonCamera mainCamera = null;
            ICameraObject mainCameraNode = null;

            RaiseMessage("Exporting cameras");
            var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
            for (int ix = 0; ix < camerasTab.Count; ++ix)
            {
                var indexer = new IntPtr(ix);
                var cameraNode = camerasTab[indexer];
                Marshal.FreeHGlobal(indexer);
                ExportCamera(gameScene, cameraNode, babylonScene);

                if (mainCamera == null && babylonScene.CamerasList.Count > 0)
                {
                    mainCameraNode = (cameraNode.MaxNode.ObjectRef as ICameraObject);
                    mainCamera = babylonScene.CamerasList[0];
                    babylonScene.activeCameraID = mainCamera.id;
                    RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true);
                }
            }

            if (mainCamera == null)
            {
                RaiseWarning("No camera defined", 1);
            }
            else
            {
                RaiseMessage(string.Format("Total: {0}", babylonScene.CamerasList.Count), Color.Gray, 1);
            }

            // Fog
            for (var index = 0; index < Loader.Core.NumAtmospheric; index++)
            {
                var atmospheric = Loader.Core.GetAtmospheric(index);

                if (atmospheric.Active(0) && atmospheric.ClassName == "Fog")
                {
                    var fog = atmospheric as IStdFog;

                    RaiseMessage("Exporting fog");

                    if (fog != null)
                    {
                        babylonScene.fogColor = fog.GetColor(0).ToArray();
                        babylonScene.fogMode = 3;
                    }
#if !MAX2015 && !MAX2016
                    else
                    {
                        var paramBlock = atmospheric.GetReference(0) as IIParamBlock;

                        babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color");
                        babylonScene.fogMode = 3;
                    }
#endif
                    if (mainCamera != null)
                    {
                        babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever);
                        babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever);
                    }
                }
            }

            // Meshes
            ReportProgressChanged(10);
            RaiseMessage("Exporting meshes");
            var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh);
            var progressionStep = 80.0f / meshes.Count;
            var progression = 10.0f;
            for (int ix = 0; ix < meshes.Count; ++ix)
            {
                var indexer = new IntPtr(ix);
                var meshNode = meshes[indexer];
                Marshal.FreeHGlobal(indexer);
                ExportMesh(gameScene, meshNode, babylonScene);


                ReportProgressChanged((int)progression);

                progression += progressionStep;

                CheckCancelled();
            }


            // Materials
            RaiseMessage("Exporting materials");
            var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials
            foreach (var mat in matsToExport)
            {
                ExportMaterial(mat, babylonScene);
                CheckCancelled();
            }
            RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1);

            // Lights
            RaiseMessage("Exporting lights");
            var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
            for (var i = 0; i < lightNodes.Count; ++i)
            {
                ExportLight(gameScene, lightNodes[new IntPtr(i)], babylonScene);
                CheckCancelled();
            }


            if (babylonScene.LightsList.Count == 0)
            {
                RaiseWarning("No light defined", 1);
                RaiseWarning("A default hemispheric light was added for your convenience", 1);
                ExportDefaultLight(babylonScene);
            }
            else
            {
                RaiseMessage(string.Format("Total: {0}", babylonScene.LightsList.Count), Color.Gray, 1);
            }

            // Skeletons
            if (skins.Count > 0)
            {
                RaiseMessage("Exporting skeletons");
                foreach (var skin in skins)
                {
                    ExportSkin(skin, babylonScene);
                }
            }

            // Actions
            babylonScene.actions = ExportNodeAction(gameScene.GetIGameNode(rawScene));

            // Output
            RaiseMessage("Saving to output file");
            babylonScene.Prepare(false);
            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
            var sb = new StringBuilder();
            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);

            await Task.Run(() =>
            {
                using (var jsonWriter = new JsonTextWriterOptimized(sw))
                {
                    jsonWriter.Formatting = Formatting.None;
                    jsonSerializer.Serialize(jsonWriter, babylonScene);
                }
                File.WriteAllText(outputFile, sb.ToString());

                if (generateManifest)
                {
                    File.WriteAllText(outputFile + ".manifest",
                        "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}");
                }
            });

            // Binary
            if (generateBinary)
            {
                RaiseMessage("Generating binary files");
                BabylonFileConverter.BinaryConverter.Convert(outputFile, Path.GetDirectoryName(outputFile) + "\\Binary",
                    message => RaiseMessage(message, 1),
                    error => RaiseError(error, 1));
            }

            ReportProgressChanged(100);
            watch.Stop();
            RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue);
        }
コード例 #2
0
        private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
        {
            if (meshNode.MaxNode.IsInstance())
            {
                return;
            }

            if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
            {
                return;
            }

            if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false))
            {
                return;
            }

            var gameMesh = meshNode.IGameObject.AsGameMesh();
            bool initialized = gameMesh.InitializeData; //needed, the property is in fact a method initializing the exporter that has wrongly been auto 
            // translated into a property because it has no parameters

            var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() };

            if (meshNode.NodeParent != null)
            {
                babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene);
            }

            // Sounds
            var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", "");
            if (!string.IsNullOrEmpty(soundName))
            {
                var filename = Path.GetFileName(soundName);

                var meshSound = new BabylonSound
                {
                    name = filename,
                    autoplay = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_autoplay", 1),
                    loop = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_loop", 1),
                    volume = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_volume", 1.0f),
                    playbackRate = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_playbackrate", 1.0f),
                    connectedMeshId = babylonMesh.id,
                    isDirectional = false,
                    spatialSound = false,
                    distanceModel = meshNode.MaxNode.GetStringProperty("babylonjs_sound_distancemodel", "linear"),
                    maxDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_maxdistance", 100f),
                    rolloffFactor = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_rolloff", 1.0f),
                    refDistance = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_refdistance", 1.0f),
                };

                var isDirectional = meshNode.MaxNode.GetBoolProperty("babylonjs_sound_directional", 0);
                
                if (isDirectional)
                {
                    meshSound.isDirectional = true;
                    meshSound.coneInnerAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneinnerangle", 360f);
                    meshSound.coneOuterAngle = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneouterangle", 360f);
                    meshSound.coneOuterGain = meshNode.MaxNode.GetFloatProperty("babylonjs_sound_coneoutergain", 1.0f);
                }

                babylonScene.SoundsList.Add(meshSound);

                try
                {
                    File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true);
                }
                catch
                {
                }
            }

            // Misc.
            babylonMesh.isVisible = meshNode.MaxNode.Renderable == 1;
            babylonMesh.pickable = meshNode.MaxNode.GetBoolProperty("babylonjs_checkpickable");
            babylonMesh.receiveShadows = meshNode.MaxNode.RcvShadows == 1;
            babylonMesh.showBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showboundingbox");
            babylonMesh.showSubMeshesBoundingBox = meshNode.MaxNode.GetBoolProperty("babylonjs_showsubmeshesboundingbox");
            babylonMesh.applyFog = meshNode.MaxNode.ApplyAtmospherics == 1;
            babylonMesh.alphaIndex = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_alphaindex", 1000);

            // Actions
            babylonMesh.actions = ExportNodeAction(meshNode);

            // Collisions
            babylonMesh.checkCollisions = meshNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions");

            var isSkinned = gameMesh.IsObjectSkinned;
            var skin = gameMesh.IGameSkin;
            var unskinnedMesh = gameMesh;
            IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true));
            List<int> boneIds = null;
            if (isSkinned)
            {
                bonesCount = skin.TotalSkinBoneCount;
                skins.Add(skin);

                skinnedNodes.Add(meshNode);
                babylonMesh.skeletonId = skins.IndexOf(skin);
                skin.GetInitSkinTM(skinInitPoseMatrix);
                boneIds = SortBones(skin);
                skinSortedBones[skin] = boneIds;
            }

            // Position / rotation / scaling
            var localTM = meshNode.GetObjectTM(0);
            if (meshNode.NodeParent != null)
            {
                var parentWorld = meshNode.NodeParent.GetObjectTM(0);
                localTM.MultiplyBy(parentWorld.Inverse);
            }

            var meshTrans = localTM.Translation;
            var meshRotation = localTM.Rotation;
            var meshScale = localTM.Scaling;
            var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions");

            babylonMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z };

            if (exportQuaternions)
            {
                babylonMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W };
            }
            else
            {
                RotationToEulerAngles(babylonMesh, meshRotation);
            }

            babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z };

            // Mesh
            RaiseMessage(meshNode.Name, 1);

            if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null)
            {
                if (unskinnedMesh.NumberOfFaces < 1)
                {
                    RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name), 2);
                }

                if (unskinnedMesh.NumberOfVerts < 3)
                {
                    RaiseError(string.Format("Mesh {0} has not enough vertices", babylonMesh.name), 2);
                }

                if (unskinnedMesh.NumberOfVerts >= 65536)
                {
                    RaiseWarning(string.Format("Mesh {0} has tmore than 65536 vertices which means that it will require specific WebGL extension to be rendered. This may impact portability of your scene on low end devices.", babylonMesh.name), 2);
                }

                // Physics
                var impostorText = meshNode.MaxNode.GetStringProperty("babylonjs_impostor", "None");

                if (impostorText != "None")
                {
                    switch (impostorText)
                    {
                        case "Sphere":
                            babylonMesh.physicsImpostor = 1;
                            break;
                        case "Box":
                            babylonMesh.physicsImpostor = 2;
                            break;
                        case "Plane":
                            babylonMesh.physicsImpostor = 3;
                            break;
                        default:
                            babylonMesh.physicsImpostor = 0;
                            break;
                    }

                    babylonMesh.physicsMass = meshNode.MaxNode.GetFloatProperty("babylonjs_mass");
                    babylonMesh.physicsFriction = meshNode.MaxNode.GetFloatProperty("babylonjs_friction", 0.2f);
                    babylonMesh.physicsRestitution = meshNode.MaxNode.GetFloatProperty("babylonjs_restitution", 0.2f);
                }

                // Material
                var mtl = meshNode.NodeMaterial;
                var multiMatsCount = 1;

                if (mtl != null)
                {
                    babylonMesh.materialId = mtl.MaxMaterial.GetGuid().ToString();

                    if (!referencedMaterials.Contains(mtl))
                    {
                        referencedMaterials.Add(mtl);
                    }

                    multiMatsCount = Math.Max(mtl.SubMaterialCount, 1);
                }

                babylonMesh.visibility = meshNode.MaxNode.GetVisibility(0, Tools.Forever);

                var vertices = new List<GlobalVertex>();
                var indices = new List<int>();
                var mappingChannels = unskinnedMesh.ActiveMapChannelNum;
                bool hasUV = false;
                bool hasUV2 = false;
                for (int i = 0; i < mappingChannels.Count; ++i)
                {
                    var indexer = new IntPtr(i);
                    var channelNum = mappingChannels[indexer];
                    if (channelNum == 1)
                    {
                        hasUV = true;
                    }
                    else if (channelNum == 2)
                    {
                        hasUV2 = true;
                    }
                }
                var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
                var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;

                var optimizeVertices = meshNode.MaxNode.GetBoolProperty("babylonjs_optimizevertices");

                // Compute normals
                List<GlobalVertex>[] verticesAlreadyExported = null;

                if (optimizeVertices)
                {
                    verticesAlreadyExported = new List<GlobalVertex>[unskinnedMesh.NumberOfVerts];
                }

                var subMeshes = new List<BabylonSubMesh>();
                var indexStart = 0;


                for (int i = 0; i < multiMatsCount; ++i)
                {
                    int materialId = meshNode.NodeMaterial == null ? 0 : meshNode.NodeMaterial.GetMaterialID(i);
                    var indexCount = 0;
                    var minVertexIndex = int.MaxValue;
                    var maxVertexIndex = int.MinValue;
                    var subMesh = new BabylonSubMesh { indexStart = indexStart, materialIndex = i };

                    if (multiMatsCount == 1)
                    {
                        for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                        {
                            var face = unskinnedMesh.GetFace(j);
                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                        }
                    }
                    else
                    {
                        ITab<IFaceEx> materialFaces = unskinnedMesh.GetFacesFromMatID(materialId);
                        for (int j = 0; j < materialFaces.Count; ++j)
                        {
                            var faceIndexer = new IntPtr(j);
                            var face = materialFaces[faceIndexer];

                            Marshal.FreeHGlobal(faceIndexer);
                            ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face, boneIds);
                        }
                    }

                    if (indexCount != 0)
                    {

                        subMesh.indexCount = indexCount;
                        subMesh.verticesStart = minVertexIndex;
                        subMesh.verticesCount = maxVertexIndex - minVertexIndex + 1;

                        indexStart += indexCount;

                        subMeshes.Add(subMesh);
                    }
                }

                if (vertices.Count >= 65536)
                {
                    RaiseWarning(string.Format("Mesh {0} has {1} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", babylonMesh.name, vertices.Count), 2);

                    if (!optimizeVertices)
                    {
                        RaiseError("You can try to optimize your object using [Try to optimize vertices] option", 2);
                    }
                }

                RaiseMessage(string.Format("{0} vertices, {1} faces", vertices.Count, indices.Count / 3), 2);

                // Buffers
                babylonMesh.positions = vertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray();
                babylonMesh.normals = vertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToArray();
                if (hasUV)
                {
                    babylonMesh.uvs = vertices.SelectMany(v => new[] { v.UV.X, 1 - v.UV.Y }).ToArray();
                }
                if (hasUV2)
                {
                    babylonMesh.uvs2 = vertices.SelectMany(v => new[] { v.UV2.X, 1 - v.UV2.Y }).ToArray();
                }

                if (skin != null)
                {
                    babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
                    babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
                }

                if (hasColor)
                {
                    babylonMesh.colors = vertices.SelectMany(v => v.Color.ToArray()).ToArray();
                    babylonMesh.hasVertexAlpha = hasAlpha;
                }

                babylonMesh.subMeshes = subMeshes.ToArray();

                // Buffers - Indices
                babylonMesh.indices = indices.ToArray();

            }

            // Instances
            var tabs = Loader.Global.NodeTab.Create();

            Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
            var instances = new List<BabylonAbstractMesh>();

            for (var index = 0; index < tabs.Count; index++)
            {
                var indexer = new IntPtr(index);
                var tab = tabs[indexer];

                Marshal.FreeHGlobal(indexer);

                if (meshNode.MaxNode.GetGuid() == tab.GetGuid())
                {
                    continue;
                }
                var instanceGameNode = scene.GetIGameNode(tab);
                if (instanceGameNode == null)
                {
                    continue;
                }
                tab.MarkAsInstance();

                var instance = new BabylonAbstractMesh { name = tab.Name };
                {
                    var instanceLocalTM = instanceGameNode.GetObjectTM(0);

                    var instanceTrans = instanceLocalTM.Translation;
                    var instanceRotation = instanceLocalTM.Rotation;
                    var instanceScale = instanceLocalTM.Scaling;

                    instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };

                    if (exportQuaternions)
                    {
                        instance.rotationQuaternion = new[] { instanceRotation.X, instanceRotation.Y, instanceRotation.Z, -instanceRotation.W };
                    }
                    else
                    {
                        RotationToEulerAngles(instance, instanceRotation);
                    }

                    instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z };
                }
                var instanceAnimations = new List<BabylonAnimation>();
                GenerateCoordinatesAnimations(meshNode, instanceAnimations);
                instance.animations = instanceAnimations.ToArray();

                instances.Add(instance);
            }

            babylonMesh.instances = instances.ToArray();

            // Animations
            var animations = new List<BabylonAnimation>();

            GenerateCoordinatesAnimations(meshNode, animations);

            if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations))
            {
                ExportFloatAnimation("visibility", animations, key => new[] { meshNode.MaxNode.GetVisibility(key, Tools.Forever) });
            }

            babylonMesh.animations = animations.ToArray();

            if (meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1))
            {
                babylonMesh.autoAnimate = true;
                babylonMesh.autoAnimateFrom = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
                babylonMesh.autoAnimateTo = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100);
                babylonMesh.autoAnimateLoop = meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1);
            }

            babylonScene.MeshesList.Add(babylonMesh);
        }
コード例 #3
0
ファイル: SceneBuilder.cs プロジェクト: BabylonJS/Babylon.js
        public void ConvertFromUnity()
        {
            ExporterWindow.ReportProgress(0, "Starting exportation process...");
            gameObjects = Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
            if (gameObjects.Length == 0)
            {
                ExporterWindow.ShowMessage("No gameobject! - Please add at least a gameobject to export");
                return;
            }

            // Create scene metadata
            SceneBuilder.Metadata = new SceneMetaData();

            // Parse all scene game objects
            var index = 0;
            var itemsCount = gameObjects.Length;
            var particleSystems = new List<BabylonExport.Entities.BabylonParticleSystem>();
            var lensFlareSystems = new List<UnityFlareSystem>();
            ExporterWindow.ReportProgress(0, "Exporting game objects from scene...");
            babylonScene.physicsEngine = (exportationOptions.DefaultPhysicsEngine == 1) ? "oimo" : "cannon";
            try
            {
                bool foundController = false;
                foreach (var gameObject in gameObjects)
                {
                    var progress = ((float)index / itemsCount);
                    index++;

                    // Unity metadata
                    var metaData = new UnityMetaData();
                    metaData.objectId = GetID(gameObject);
                    metaData.objectName = gameObject.name;
                    metaData.tagName = gameObject.tag;
                    metaData.layerIndex = gameObject.layer;
                    metaData.layerName = LayerMask.LayerToName(gameObject.layer);

                    // Export hooking
                    var exportObject = gameObject;
                    var exportOptions = exportationOptions;
                    BabylonScene sceneBuilder = babylonScene;
                    if (SceneController != null)
                    {
                        SceneController.OnExportGameObject(ref exportOptions, ref exportObject, ref metaData, ref sceneBuilder, OutputPath);
                    }

                    // Components tags
                    string componentTags = String.Empty;
                    if (!String.IsNullOrEmpty(gameObject.tag) && !gameObject.tag.Equals("Untagged", StringComparison.OrdinalIgnoreCase))
                    {
                        componentTags = gameObject.tag;
                    }

                    // Navigation area
                    metaData.areaIndex = -1;
                    bool navigationStatic = GameObjectUtility.AreStaticEditorFlagsSet(gameObject, StaticEditorFlags.NavigationStatic);
                    if (navigationStatic)
                    {
                        metaData.areaIndex = GameObjectUtility.GetNavMeshArea(gameObject);
                    }

                    // Navigation agent
                    metaData.navAgent = null;
                    var navigationAgent = gameObject.GetComponent<NavMeshAgent>();
                    if (navigationAgent != null)
                    {
                        componentTags += " [NAVAGENT]";
                        Dictionary<string, object> agentInfo = new Dictionary<string, object>();
                        agentInfo.Add("name", navigationAgent.name);
                        agentInfo.Add("radius", navigationAgent.radius);
                        agentInfo.Add("height", navigationAgent.height);
                        agentInfo.Add("speed", navigationAgent.speed);
                        agentInfo.Add("acceleration", navigationAgent.acceleration);
                        agentInfo.Add("angularSpeed", navigationAgent.angularSpeed);
                        agentInfo.Add("areaMask", navigationAgent.areaMask);
                        agentInfo.Add("autoBraking", navigationAgent.autoBraking);
                        agentInfo.Add("autoTraverseOffMeshLink", navigationAgent.autoTraverseOffMeshLink);
                        agentInfo.Add("avoidancePriority", navigationAgent.avoidancePriority);
                        agentInfo.Add("baseOffset", navigationAgent.baseOffset);
                        agentInfo.Add("obstacleAvoidanceType", navigationAgent.obstacleAvoidanceType.ToString());
                        agentInfo.Add("stoppingDistance", navigationAgent.stoppingDistance);
                        metaData.navAgent = agentInfo;
                    }

                    // Navigation link
                    metaData.meshLink = null;
                    var navigationLink = gameObject.GetComponent<OffMeshLink>();
                    if (navigationLink != null)
                    {
                        componentTags += " [MESHLINK]";
                        Dictionary<string, object> linkInfo = new Dictionary<string, object>();
                        linkInfo.Add("name", navigationLink.name);
                        linkInfo.Add("activated", navigationLink.activated);
                        linkInfo.Add("area", navigationLink.area);
                        linkInfo.Add("autoUpdatePositions", navigationLink.autoUpdatePositions);
                        linkInfo.Add("biDirectional", navigationLink.biDirectional);
                        linkInfo.Add("costOverride", navigationLink.costOverride);
                        linkInfo.Add("occupied", navigationLink.occupied);
                        linkInfo.Add("start", GetTransformPropertyValue(navigationLink.startTransform));
                        linkInfo.Add("end", GetTransformPropertyValue(navigationLink.endTransform));
                        metaData.meshLink = linkInfo;
                    }

                    // Navigation obstacle
                    metaData.meshObstacle = null;
                    var navigationObstacle = gameObject.GetComponent<NavMeshObstacle>();
                    if (navigationObstacle != null)
                    {
                        componentTags += " [MESHOBSTACLE]";
                        Dictionary<string, object> obstacleInfo = new Dictionary<string, object>();
                        obstacleInfo.Add("name", navigationObstacle.name);
                        obstacleInfo.Add("carving", navigationObstacle.carving);
                        obstacleInfo.Add("carveOnlyStationary", navigationObstacle.carveOnlyStationary);
                        obstacleInfo.Add("carvingMoveThreshold", navigationObstacle.carvingMoveThreshold);
                        obstacleInfo.Add("carvingTimeToStationary", navigationObstacle.carvingTimeToStationary);
                        obstacleInfo.Add("shape", navigationObstacle.shape.ToString());
                        obstacleInfo.Add("radius", navigationObstacle.radius);
                        obstacleInfo.Add("center", navigationObstacle.center.ToFloat());
                        obstacleInfo.Add("size", navigationObstacle.size.ToFloat());
                        metaData.meshObstacle = obstacleInfo;
                    }

                    // Tags component
                    var tagsComponent = gameObject.GetComponent<BabylonTagsComponent>();
                    if (tagsComponent != null)
                    {
                        if (!String.IsNullOrEmpty(tagsComponent.babylonTags))
                        {
                            componentTags += (" " + tagsComponent.babylonTags);
                        }
                    }

                    // Script components
                    var gameComponents = gameObject.GetComponents<BabylonScriptComponent>();
                    if (gameComponents != null)
                    {
                        var components = new List<object>();
                        foreach (var gameComponent in gameComponents)
                        {
                            Type componentType = gameComponent.GetType();
                            string componentName = componentType.FullName;
                            var component = new UnityScriptComponent();
                            MonoScript componentScript = MonoScript.FromMonoBehaviour(gameComponent);
                            component.order = MonoImporter.GetExecutionOrder(componentScript);
                            component.name = componentName;
                            component.klass = gameComponent.babylonClass;
                            component.update = (gameComponent.updateOption == BabylonTickOptions.EnableTick);
                            component.controller = (gameComponent is BabylonSceneController);
                            if (component.controller == true)
                            {
                                component.order = -1;
                                if (foundController == false)
                                {
                                    foundController = true;
                                    componentTags += " [CONTROLLER]";
                                    object userInterface = null;
                                    BabylonSceneController scx = (gameComponent as BabylonSceneController);
                                    EmbeddedAsset guiAsset = scx.sceneOptions.graphicUserInterface;
                                    if (guiAsset != null && scx.sceneOptions.userInterfaceMode != BabylonGuiMode.None)
                                    {
                                        userInterface = GetEmbeddedAssetPropertyValue(guiAsset);
                                    }
                                    SceneBuilder.Metadata.properties.Add("autoDraw", scx.sceneOptions.autoDrawInterface);
                                    SceneBuilder.Metadata.properties.Add("interfaceMode", scx.sceneOptions.userInterfaceMode.ToString());
                                    SceneBuilder.Metadata.properties.Add("userInterface", userInterface);
                                    SceneBuilder.Metadata.properties.Add("controllerPresent", true);
                                    SceneBuilder.Metadata.properties.Add("controllerObjectId", metaData.objectId);
                                }
                                else
                                {
                                    Debug.LogError("Duplicate scene controller detected: " + component.name);
                                }
                            }
                            FieldInfo[] componentFields = componentType.GetFields();
                            if (componentFields != null)
                            {
                                foreach (var componentField in componentFields)
                                {
                                    var componentAttribute = (BabylonPropertyAttribute)Attribute.GetCustomAttribute(componentField, typeof(BabylonPropertyAttribute));
                                    if (componentAttribute != null && componentField.Name != "babylonClass")
                                    {
                                        component.properties.Add(componentField.Name, GetComponentPropertyValue(componentField, gameComponent));
                                    }
                                }
                            }
                            gameComponent.OnExportProperties(ref exportOptions, ref exportObject, ref component.properties, OutputPath);
                            components.Add(component);
                        }
                        if (components.Count > 0)
                        {
                            metaData.components = components;
                        }
                    }

                    // Format tags
                    if (!String.IsNullOrEmpty(componentTags))
                    {
                        componentTags = componentTags.Trim();
                    }

                    // Audio sources
                    var audioComponents = gameObject.GetComponents<BabylonAudioSource>();
                    if (audioComponents != null)
                    {
                        foreach (var item in audioComponents)
                        {
                            if (item != null && item.exportAudio && item.sound != null)
                            {
                                string soundPath = AssetDatabase.GetAssetPath(item.sound);
                                if (!String.IsNullOrEmpty(soundPath))
                                {
                                    string soundName = Path.GetFileName(soundPath).Replace(" ", "");
                                    string outputFile = Path.Combine(OutputPath, soundName);
                                    if (File.Exists(soundPath))
                                    {
                                        File.Copy(soundPath, outputFile, true);
                                        var sound = new BabylonSound();
                                        sound.name = soundName;
                                        sound.volume = item.options.volume;
                                        sound.playbackRate = item.options.playbackRate;
                                        sound.autoplay = item.options.autoplay;
                                        sound.loop = item.options.loop;
                                        sound.soundTrackId = item.options.soundTrackId;
                                        sound.spatialSound = item.options.spatialSound;
                                        sound.position = item.options.position.ToFloat();
                                        sound.refDistance = item.options.refDistance;
                                        sound.rolloffFactor = item.options.rolloffFactor;
                                        sound.maxDistance = item.options.maxDistance;
                                        sound.distanceModel = item.options.distanceModel;
                                        sound.panningModel = item.options.panningModel;
                                        sound.isDirectional = item.options.isDirectional;
                                        sound.coneInnerAngle = item.options.coneInnerAngle;
                                        sound.coneOuterAngle = item.options.coneOuterAngle;
                                        sound.coneOuterGain = item.options.coneOuterGain;
                                        sound.localDirectionToMesh = item.options.directionToMesh.ToFloat();
                                        babylonScene.SoundsList.Add(sound);
                                    }
                                    else
                                    {
                                        Debug.LogError("Fail to locate audio file: " + soundPath);
                                    }
                                }
                                else
                                {
                                    Debug.LogError("Null audio clip path for: " + item.sound.name);
                                }
                            }
                        }
                    }

                    // Terrain meshes
                    var terrainMesh = gameObject.GetComponent<Terrain>();
                    if (terrainMesh != null)
                    {
                        ConvertUnityTerrainToBabylon(terrainMesh, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        continue;
                    }

                    // Collision meshes
                    BabylonMesh collisionMesh = null;
                    var collider = gameObject.GetComponent<Collider>();
                    if (collider != null)
                    {
                        if (collider.enabled)
                        {
                            int segments = 12;
                            BabylonColliderDetail detail = (BabylonColliderDetail)exportationOptions.DefaultColliderDetail;
                            var collisionData = new UnityMetaData();
                            collisionData.objectId = Guid.NewGuid().ToString();
                            collisionData.objectName = gameObject.name + "_Metadata";
                            if (collider is MeshCollider)
                            {
                                var meshCollider = collider as MeshCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[MESHCOLLIDER]";
                                // Generate Mesh Collider Geometry
                                if(!meshCollider.sharedMesh)
                                {
                                    UnityEngine.Debug.LogWarning(meshCollider.gameObject+" has a Mesh Collider component without a mesh");
                                }
                                else
                                {
                                    Tools.GenerateBabylonMeshData(meshCollider.sharedMesh, collisionMesh);
                                }
                                collisionMesh.position = Vector3.zero.ToFloat();
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                float factorX = 1f, factorY = 1f, factorZ = 1f;
                                if (meshCollider.inflateMesh && meshCollider.skinWidth > 0f)
                                {
                                    Vector3 localScale = gameObject.transform.localScale;
                                    factorX += (meshCollider.skinWidth / localScale.x);
                                    factorY += (meshCollider.skinWidth / localScale.y);
                                    factorZ += (meshCollider.skinWidth / localScale.z);
                                }
                                collisionMesh.scaling = new Vector3(factorX, factorY, factorZ).ToFloat();
                                // Export Mesh Collider Metadata
                                collisionData.tagName = "MeshCollider";
                                collisionData.properties.Add("type", "Mesh");
                                collisionData.properties.Add("convex", meshCollider.convex);
                                collisionData.properties.Add("inflateMesh", meshCollider.inflateMesh);
                                collisionData.properties.Add("skinWidth", meshCollider.skinWidth);
                            }
                            else if (collider is CapsuleCollider)
                            {
                                var capsuleCollider = collider as CapsuleCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[CAPSULECOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 12;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 8;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 6;
                                        break;
                                    default:
                                        segments = 12;
                                        break;
                                }
                                // Generate Capsule Collider Geometry
                                Mesh capsuleMesh = Tools.CreateCapsuleMesh(capsuleCollider.height, capsuleCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(capsuleMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = capsuleCollider.center.x;
                                collisionMesh.position[1] = capsuleCollider.center.y;
                                collisionMesh.position[2] = capsuleCollider.center.z;
                                collisionMesh.rotation = new float[3];
                                collisionMesh.rotation[0] = (capsuleCollider.direction == 2) ? 90f * (float)Math.PI / 180f : 0f;
                                collisionMesh.rotation[1] = 0f;
                                collisionMesh.rotation[2] = (capsuleCollider.direction == 0) ? 90f * (float)Math.PI / 180f : 0f;
                                collisionMesh.scaling = new Vector3(1, 1, 1).ToFloat();
                                // Export Capsule Collider Metadata
                                collisionData.tagName = "CapsuleCollider";
                                collisionData.properties.Add("type", "Capsule");
                                collisionData.properties.Add("center", capsuleCollider.center.ToFloat());
                                collisionData.properties.Add("radius", capsuleCollider.radius);
                                collisionData.properties.Add("height", capsuleCollider.height);
                                collisionData.properties.Add("direction", capsuleCollider.direction);
                            }
                            else if (collider is SphereCollider)
                            {
                                var sphereCollider = collider as SphereCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[SPHERECOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 12;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 8;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 6;
                                        break;
                                    default:
                                        segments = 12;
                                        break;
                                }
                                // Generate Sphere Collider Geometry
                                Mesh sphereMesh = Tools.CreateSphereMesh(sphereCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(sphereMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = sphereCollider.center.x;
                                collisionMesh.position[1] = sphereCollider.center.y;
                                collisionMesh.position[2] = sphereCollider.center.z;
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Sphere Collider Metadata
                                collisionData.tagName = "SphereCollider";
                                collisionData.properties.Add("type", "Sphere");
                                collisionData.properties.Add("center", sphereCollider.center.ToFloat());
                                collisionData.properties.Add("radius", sphereCollider.radius);
                            }
                            else if (collider is WheelCollider)
                            {
                                var wheelCollider = collider as WheelCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[WHEELCOLLIDER]";
                                switch (detail)
                                {
                                    case BabylonColliderDetail.FullResolution:
                                        segments = 128;
                                        break;
                                    case BabylonColliderDetail.HighResolution:
                                        segments = 64;
                                        break;
                                    case BabylonColliderDetail.MediumResolution:
                                        segments = 48;
                                        break;
                                    case BabylonColliderDetail.LowResolution:
                                        segments = 32;
                                        break;
                                    case BabylonColliderDetail.VeryLowResolution:
                                        segments = 24;
                                        break;
                                    case BabylonColliderDetail.MinimumResolution:
                                        segments = 16;
                                        break;
                                    default:
                                        segments = 32;
                                        break;
                                }
                                // Generate Wheel Collider Geometry
                                Mesh wheelMesh = Tools.CreateWheelMesh(wheelCollider.suspensionDistance, wheelCollider.radius, segments);
                                Tools.GenerateBabylonMeshData(wheelMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = wheelCollider.center.x;
                                collisionMesh.position[1] = wheelCollider.center.y;
                                collisionMesh.position[2] = wheelCollider.center.z;
                                collisionMesh.rotation = new float[3];
                                collisionMesh.rotation[0] = 0f;
                                collisionMesh.rotation[1] = 0f;
                                collisionMesh.rotation[2] = 90f * (float)Math.PI / 180;
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Wheel Collider Metadata
                                collisionData.tagName = "WheelCollider";
                                collisionData.properties.Add("type", "Wheel");
                                collisionData.properties.Add("center", wheelCollider.center.ToFloat());
                                collisionData.properties.Add("radius", wheelCollider.radius);
                            }
                            else if (collider is BoxCollider)
                            {
                                var boxCollider = collider as BoxCollider;
                                collisionMesh = new BabylonMesh();
                                collisionMesh.tags = "[BOXCOLLIDER]";
                                // Generate Box Collider Geometry
                                Mesh boxMesh = Tools.CreateBoxMesh(boxCollider.size.x, boxCollider.size.y, boxCollider.size.z);
                                Tools.GenerateBabylonMeshData(boxMesh, collisionMesh);
                                collisionMesh.position = new float[3];
                                collisionMesh.position[0] = boxCollider.center.x;
                                collisionMesh.position[1] = boxCollider.center.y;
                                collisionMesh.position[2] = boxCollider.center.z;
                                collisionMesh.rotation = Vector3.zero.ToFloat();
                                collisionMesh.scaling = new Vector3(1f, 1f, 1f).ToFloat();
                                // Export Box Collider Metadata
                                collisionData.tagName = "BoxCollider";
                                collisionData.properties.Add("type", "Box");
                                collisionData.properties.Add("center", boxCollider.center.ToFloat());
                                collisionData.properties.Add("size", boxCollider.size.ToFloat());
                            }
                            if (collisionMesh != null)
                            {
                                collisionMesh.id = Guid.NewGuid().ToString();
                                collisionMesh.name = gameObject.name + "_Collider";
                                // Default Check Collisions False
                                collisionMesh.checkCollisions = false;
                                collisionMesh.isVisible = false;
                                collisionData.properties.Add("parrentId", metaData.objectId);
                                collisionData.properties.Add("transform", GetTransformPropertyValue(gameObject.transform));
                                collisionMesh.metadata = collisionData;
                                babylonScene.MeshesList.Add(collisionMesh);
                                SceneBuilder.Metadata.properties["hasCollisionMeshes"] = true;
                            }
                        }
                    }

                    // Static meshes
                    var meshFilter = gameObject.GetComponent<MeshFilter>();
                    if (meshFilter != null)
                    {
                        ConvertUnityMeshToBabylon(meshFilter.sharedMesh, meshFilter.transform, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                        continue;
                    }

                    // Skinned meshes
                    var skinnedMesh = gameObject.GetComponent<SkinnedMeshRenderer>();
                    if (skinnedMesh != null)
                    {
                        var babylonMesh = ConvertUnityMeshToBabylon(skinnedMesh.sharedMesh, skinnedMesh.transform, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                        var skeleton = ConvertUnitySkeletonToBabylon(skinnedMesh.bones, skinnedMesh.sharedMesh.bindposes, skinnedMesh.transform, gameObject, progress);
                        babylonMesh.skeletonId = skeleton.id;
                        ExportSkeletonAnimation(skinnedMesh, babylonMesh, skeleton);
                        continue;
                    }

                    // Scene lights
                    var light = gameObject.GetComponent<Light>();
                    if (light != null)
                    {
                        ConvertUnityLightToBabylon(light, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        continue;
                    }

                    // Scene cameras
                    var camera = gameObject.GetComponent<Camera>();
                    if (camera != null)
                    {
                        ConvertUnityCameraToBabylon(camera, gameObject, progress, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags);
                        if (SceneController != null && SceneController.skyboxOptions.exportSkybox)
                        {
                            ConvertUnitySkyboxToBabylon(camera, progress);
                        }
                        continue;
                    }

                    // Empty objects
                    ConvertUnityEmptyObjectToBabylon(gameObject, ref metaData, ref particleSystems, ref lensFlareSystems, ref componentTags, collisionMesh, collider);
                }

                // Materials
                foreach (var mat in materialsDictionary)
                {
                    babylonScene.MaterialsList.Add(mat.Value);
                }
                foreach (var multiMat in multiMatDictionary)
                {
                    babylonScene.MultiMaterialsList.Add(multiMat.Value);
                }

                // Collisions
                if (exportationOptions.ExportCollisions)
                {
                    babylonScene.workerCollisions = exportationOptions.WorkerCollisions;
                    if (SceneController != null) {
                        babylonScene.gravity = SceneController.sceneOptions.defaultGravity.ToFloat();
                    }
                }

                // Babylon Physics
                if (exportationOptions.ExportPhysics)
                {
                    babylonScene.physicsEnabled = true;
                    if (SceneController != null) {
                        babylonScene.physicsGravity = SceneController.sceneOptions.defaultGravity.ToFloat();
                    }
                }

                // Scene Controller
                if (SceneController != null)
                {
                    Color ambientColor = SceneController.sceneOptions.ambientColor;
                    float ambientLevel = SceneController.lightingOptions.lightLevel;
                    Color ambientSpecular = SceneController.lightingOptions.specularColor;
                    babylonScene.autoClear = SceneController.sceneOptions.autoClear;
                    int fogmode = 0;
                    if (RenderSettings.fog)
                    {
                        switch (RenderSettings.fogMode)
                        {
                            case FogMode.Exponential:
                                fogmode = 1;
                                break;
                            case FogMode.ExponentialSquared:
                                fogmode = 2;
                                break;
                            case FogMode.Linear:
                                fogmode = 3;
                                break;
                        }
                    }
                    babylonScene.fogMode = fogmode;
                    babylonScene.fogDensity = RenderSettings.fogDensity;
                    babylonScene.fogColor = RenderSettings.fogColor.ToFloat();
                    babylonScene.fogStart = RenderSettings.fogStartDistance;
                    babylonScene.fogEnd = RenderSettings.fogEndDistance;
                    if (exportationOptions.DefaultLightmapMode != (int)BabylonLightmapMode.FullLightBaking && SceneController.lightingOptions.lightMode == BabylonAmbientLighting.UnityAmbientLighting)
                    {
                        var ambientLight = new BabylonLight
                        {
                            name = "Ambient Light",
                            id = Guid.NewGuid().ToString(),
                            parentId = null,
                            metadata = null,
                            position = null,
                            exponent = 1.0f,
                            angle = 0.0f,
                            type = 3
                        };
                        var ambientDirection = new Vector3(0.0f, 1.0f, 0.0f);
                        Color ambientDiffuse = (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Skybox) ? RenderSettings.ambientSkyColor : RenderSettings.ambientLight;
                        ambientLight.intensity = RenderSettings.ambientIntensity * ambientLevel;
                        ambientLight.direction = ambientDirection.ToFloat(); ;
                        ambientLight.diffuse = ambientDiffuse.ToFloat();
                        ambientLight.specular = ambientSpecular.ToFloat();
                        ambientLight.groundColor = RenderSettings.ambientGroundColor.ToFloat();
                        babylonScene.ambientColor = ambientColor.ToFloat();
                        babylonScene.LightsList.Add(ambientLight);
                        ExporterWindow.ReportProgress(0, "Exporting ambient light intensity at: " + ambientLight.intensity.ToString());
                    }
                    if (SceneController.sceneOptions.navigationMesh == BabylonNavigationMesh.EnableNavigation)
                    {
                        ExporterWindow.ReportProgress(0, "Parsing scene navigation mesh...");
                        NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
                        if (triangulatedNavMesh.vertices != null && triangulatedNavMesh.vertices.Length > 0 && triangulatedNavMesh.indices != null && triangulatedNavMesh.indices.Length > 0)
                        {
                            int vertexCount = triangulatedNavMesh.vertices.Length;
                            if (vertexCount <= SceneBuilder.MAX_VERTEX_COUNT)
                            {
                                ExporterWindow.ReportProgress(0, "Generating navigation mesh vertices: " + vertexCount.ToString());
                                var navData = new UnityMetaData();
                                navData.type = "NavMesh";
                                navData.objectId = Guid.NewGuid().ToString();
                                navData.objectName = "Navigation_Mesh";
                                var areaTable = new List<object>();
                                string[] areaNavigation = GameObjectUtility.GetNavMeshAreaNames();
                                foreach (string areaName in areaNavigation)
                                {
                                    var bag = new Dictionary<string, object>();
                                    int areaIndex = NavMesh.GetAreaFromName(areaName);
                                    float areaCost = NavMesh.GetAreaCost(areaIndex);
                                    bag.Add("index", areaIndex);
                                    bag.Add("area", areaName);
                                    bag.Add("cost", areaCost);
                                    areaTable.Add(bag);
                                }
                                navData.properties.Add("table", areaTable);
                                navData.properties.Add("areas", triangulatedNavMesh.areas);

                                Mesh mesh = new Mesh();
                                mesh.name = "sceneNavigationMesh";
                                mesh.vertices = triangulatedNavMesh.vertices;
                                mesh.triangles = triangulatedNavMesh.indices;
                                mesh.RecalculateNormals();

                                BabylonMesh babylonMesh = new BabylonMesh();
                                babylonMesh.tags = "[NAVMESH]";
                                babylonMesh.metadata = navData;
                                babylonMesh.name = mesh.name;
                                babylonMesh.id = Guid.NewGuid().ToString();
                                babylonMesh.parentId = null;
                                babylonMesh.position = Vector3.zero.ToFloat();
                                babylonMesh.rotation = Vector3.zero.ToFloat();
                                babylonMesh.scaling = new Vector3(1, 1, 1).ToFloat();
                                babylonMesh.isVisible = false;
                                babylonMesh.visibility = 0.75f;
                                babylonMesh.checkCollisions = false;
                                Tools.GenerateBabylonMeshData(mesh, babylonMesh);
                                babylonScene.MeshesList.Add(babylonMesh);
                                SceneBuilder.Metadata.properties["hasNavigationMesh"] = true;
                            }
                            else
                            {
                                UnityEngine.Debug.LogError("Navigation mesh exceeds max (65000) vertex limit: " + vertexCount.ToString());
                            }
                        }
                    }
                    if (SceneController.sceneOptions.particleSystems)
                    {
                        if (particleSystems != null && particleSystems.Count > 0)
                        {
                            babylonScene.particleSystems = particleSystems.ToArray();
                        }
                    }
                    if (SceneController.sceneOptions.lensFlareSystems)
                    {
                        if (lensFlareSystems != null && lensFlareSystems.Count > 0)
                        {
                            var lfs_buffer = new List<BabylonLensFlareSystem>();
                            foreach (var ulfs in lensFlareSystems)
                            {
                                var lfs = new BabylonLensFlareSystem();
                                lfs.borderLimit = ulfs.borderLimit;
                                lfs.emitterId = ulfs.emitterId;
                                var lfx = new List<BabylonLensFlare>();
                                foreach (var ulf in ulfs.lensFlares)
                                {
                                    var lf = new BabylonLensFlare();
                                    lf.textureName = ulf.textureName;
                                    lf.position = ulf.position;
                                    lf.color = ulf.color;
                                    lf.size = ulf.size;
                                    lfx.Add(lf);
                                }
                                lfs.flares = lfx.ToArray();
                                lfs_buffer.Add(lfs);
                            }
                            babylonScene.lensFlareSystems = lfs_buffer.ToArray();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }
            finally
            {
                babylonScene.metadata = SceneBuilder.Metadata;
            }
        }