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); }
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); }
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; } }