private BabylonCamera ExportCameraAnimations(BabylonCamera babylonCamera, IIGameCamera camera, BabylonExporter exporter) { var animations = new List <BabylonAnimation>(); int numProps = camera.IPropertyContainer.NumberOfProperties; for (int i = 0; i < numProps; ++i) { IIGameProperty property = camera.IPropertyContainer.GetProperty(i); if (property == null) { continue; } IParamDef paramDef = property.MaxParamBlock2?.GetParamDef(property.ParamID); string propertyName = property.Name.ToUpperInvariant(); switch (propertyName) { default: break; } } babylonCamera.animations = animations.ToArray(); return(babylonCamera); }
void DumpCameras(NovaScene scene, BabylonScene babylonScene) { foreach (NovaCamera camera in scene.Cameras) { var babylonCamera = new BabylonCamera(); babylonScene.CamerasList.Add(babylonCamera); babylonCamera.name = camera.Name; babylonCamera.id = camera.ID.ToString(); babylonCamera.parentId = camera.ParentEntity == null ? "" : camera.ParentEntity.ID.ToString(); babylonCamera.lockedTargetId = camera.Target == null ? "" : camera.Target.ID.ToString(); babylonCamera.position = camera.Position.ToArray(); babylonCamera.rotation = camera.Rotation.ToArray(); babylonCamera.fov = camera.FOV; babylonCamera.minZ = camera.NearClip; babylonCamera.maxZ = camera.FarClip; babylonCamera.inertia = camera.Inertia; babylonCamera.speed = camera.Speed; babylonCamera.checkCollisions = camera.CheckCollisions; babylonCamera.applyGravity = camera.ApplyGravity; babylonCamera.ellipsoid = camera.EllipsoidVector.ToArray(); // Animations var animations = new List <BabylonAnimation>(); // Position if (!DumpInterpolator("Position animation", "position", camera.PositionInterpolator, scene, animations)) { DumpInterpolator("PositionX animation", "position.x", camera.PositionXInterpolator, scene, animations); DumpInterpolator("PositionY animation", "position.y", camera.PositionYInterpolator, scene, animations); DumpInterpolator("PositionZ animation", "position.z", camera.PositionZInterpolator, scene, animations); } babylonCamera.animations = animations.ToArray(); babylonCamera.autoAnimate = camera.AutoAnimate; if (camera.AutoAnimate) { babylonCamera.autoAnimateFrom = camera.AnimationStartKey; if (camera.AnimationEndKey == -1) { babylonCamera.autoAnimateTo = scene.AnimationKeyMax / scene.AnimationKeyStep; babylonCamera.autoAnimateLoop = true; } else { babylonCamera.autoAnimateTo = camera.AnimationEndKey; } } } if (scene.ActiveCamera != null) { babylonScene.activeCameraID = scene.ActiveCamera.ID.ToString(); } }
private BabylonCamera ExportCamera(Node cameraNode, BabylonScene babylonScene) { var maxCamera = (cameraNode.Object as Camera)._Camera; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, true); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.GetGuid().ToString(); if (cameraNode.HasParent()) { babylonCamera.parentId = cameraNode.Parent.GetGuid().ToString(); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Interval.Forever._IInterval)); babylonCamera.minZ = maxCamera.GetEnvRange(0, 0, Interval.Forever._IInterval); babylonCamera.maxZ = maxCamera.GetEnvRange(0, 1, Interval.Forever._IInterval); if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Control babylonCamera.speed = cameraNode._Node.GetFloatProperty("babylonjs_speed"); babylonCamera.inertia = cameraNode._Node.GetFloatProperty("babylonjs_inertia"); // Collisions babylonCamera.checkCollisions = cameraNode._Node.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode._Node.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode._Node.GetVector3Property("babylonjs_ellipsoid"); // Position var wm = cameraNode.GetWorldMatrix(0, cameraNode.HasParent()); var position = wm.Trans; babylonCamera.position = position.ToArraySwitched(); // Target var target = cameraNode._Node.Target; if (target != null) { babylonCamera.lockedTargetId = target.GetGuid().ToString(); } else { var dir = wm.GetRow(2).MultiplyBy(-1); babylonCamera.target = dir.ToArraySwitched(); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }
private void ConvertUnityCameraToBabylon(Camera camera, float progress) { ExporterWindow.ReportProgress(progress, "Exporting camera: " + camera.name); BabylonCamera babylonCamera = new BabylonCamera { name = camera.name, id = GetID(camera.gameObject), fov = camera.fieldOfView * (float)Math.PI / 180, minZ = camera.nearClipPlane, maxZ = camera.farClipPlane, parentId = GetParentID(camera.transform), position = camera.transform.localPosition.ToFloat() }; var target = new Vector3(0, 0, 1); var transformedTarget = camera.transform.TransformDirection(target); babylonCamera.target = (camera.transform.position + transformedTarget).ToFloat(); babylonScene.CamerasList.Add(babylonCamera); if (Camera.main == camera) { babylonScene.activeCameraID = babylonCamera.id; babylonScene.clearColor = camera.backgroundColor.ToFloat(); } // Animations ExportAnimations(camera.transform, babylonCamera); // Collisions if (exportationOptions.ExportCollisions) { babylonCamera.checkCollisions = true; babylonCamera.applyGravity = true; babylonCamera.ellipsoid = exportationOptions.CameraEllipsoid.ToFloat(); } }
public bool ExportBabylonExtension <T>(T babylonObject, ref BabylonScene babylonScene, BabylonExporter exporter) { var cameraNode = babylonObject as Autodesk.Max.IIGameCamera; bool isGLTFExported = exporter.exportParameters.outputFormat == "gltf"; // todo: MaterialUtilities class should be splitted as the wrapper contains more idwrapper then the materials one if (isGLTFExported && FlightSimCameraUtilities.class_ID.Equals(new MaterialUtilities.ClassIDWrapper(cameraNode.CameraTarget.MaxNode.ClassID))) { var id = cameraNode.CameraTarget.MaxNode.GetGuid().ToString(); // add a basic babylon material to the list to forward the max material reference var babylonCamera = new BabylonCamera();//(id) //{ // maxGameMaterial = materialNode, // name = materialNode.MaterialName //}; babylonCamera = ExportCameraAnimations(babylonCamera, cameraNode, exporter); babylonScene.CamerasList.Add(babylonCamera); return(true); } return(false); }
void DumpCameras(NovaScene scene, BabylonScene babylonScene) { foreach (NovaCamera camera in scene.Cameras) { var babylonCamera = new BabylonCamera(); babylonScene.CamerasList.Add(babylonCamera); babylonCamera.name = camera.Name; babylonCamera.id = camera.ID.ToString(); babylonCamera.parentId = camera.ParentEntity == null ? "" : camera.ParentEntity.ID.ToString(); babylonCamera.lockedTargetId = camera.Target == null ? "" : camera.Target.ID.ToString(); babylonCamera.position = camera.Position.ToArray(); babylonCamera.rotation = camera.Rotation.ToArray(); babylonCamera.fov = camera.FOV; babylonCamera.minZ = camera.NearClip; babylonCamera.maxZ = camera.FarClip; babylonCamera.inertia = camera.Inertia; babylonCamera.speed = camera.Speed; babylonCamera.checkCollisions = camera.CheckCollisions; babylonCamera.applyGravity = camera.ApplyGravity; babylonCamera.ellipsoid = camera.EllipsoidVector.ToArray(); // Animations var animations = new List<BabylonAnimation>(); // Position if (!DumpInterpolator("Position animation", "position", camera.PositionInterpolator, scene, animations)) { DumpInterpolator("PositionX animation", "position.x", camera.PositionXInterpolator, scene, animations); DumpInterpolator("PositionY animation", "position.y", camera.PositionYInterpolator, scene, animations); DumpInterpolator("PositionZ animation", "position.z", camera.PositionZInterpolator, scene, animations); } babylonCamera.animations = animations.ToArray(); babylonCamera.autoAnimate = camera.AutoAnimate; if (camera.AutoAnimate) { babylonCamera.autoAnimateFrom = camera.AnimationStartKey; if (camera.AnimationEndKey == -1) { babylonCamera.autoAnimateTo = scene.AnimationKeyMax / scene.AnimationKeyStep; babylonCamera.autoAnimateLoop = true; } else { babylonCamera.autoAnimateTo = camera.AnimationEndKey; } } } if (scene.ActiveCamera != null) { babylonScene.activeCameraID = scene.ActiveCamera.ID.ToString(); } }
public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, Form callerForm) { IsCancelled = false; RaiseMessage("Exportation started", Color.Blue); ReportProgressChanged(0); var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile)); var maxScene = Loader.Core.RootNode; alreadyExportedTextures.Clear(); 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 = maxScene.GetVector3Property("babylonjs_gravity"); exportQuaternionsInsteadOfEulers = maxScene.GetBoolProperty("babylonjs_exportquaternions", 1); // Cameras BabylonCamera mainCamera = null; RaiseMessage("Exporting cameras"); foreach (var cameraNode in maxScene.NodesListBySuperClass(SClass_ID.Camera)) { if (onlySelected && !cameraNode.Selected) { continue; } ExportCamera(cameraNode, babylonScene); if (mainCamera == null && babylonScene.CamerasList.Count > 0) { 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; if (fog != null) { RaiseMessage("Exporting fog"); babylonScene.fogColor = fog.GetColor(0).ToArray(); babylonScene.fogDensity = fog.GetDensity(0); babylonScene.fogMode = fog.GetType_ == 0 ? 3 : 1; if (mainCamera != null) { babylonScene.fogStart = mainCamera.minZ * fog.GetNear(0); babylonScene.fogEnd = mainCamera.maxZ * fog.GetFar(0); } } } } // Meshes ReportProgressChanged(10); RaiseMessage("Exporting meshes"); var meshes = maxScene.NodesListBySuperClasses(new[] { SClass_ID.Geomobject, SClass_ID.Helper }); var progressionStep = 80.0f / meshes.Count(); var progression = 10.0f; foreach (var meshNode in meshes) { if (onlySelected && !meshNode.Selected) { continue; } Tools.PreparePipeline(meshNode, true); ExportMesh(meshNode, babylonScene); Tools.PreparePipeline(meshNode, false); progression += progressionStep; ReportProgressChanged((int)progression); CheckCancelled(); } RaiseMessage(string.Format("Total: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // 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"); foreach (var lightNode in maxScene.NodesListBySuperClass(SClass_ID.Light)) { if (onlySelected && !lightNode.Selected) { continue; } ExportLight(lightNode, 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); skin.Dispose(); } } // 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}"); } }); ReportProgressChanged(100); watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
public void Export(string outputFile) { RaiseMessage("Exportation started"); ReportProgressChanged(25); var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile)); var maxScene = Kernel.Scene; alreadyExportedTextures.Clear(); if (!Directory.Exists(babylonScene.OutputPath)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } // Global babylonScene.autoClear = true; babylonScene.clearColor = Loader.Core.GetBackGround(0, Interval.Forever._IInterval).ToArray(); babylonScene.ambientColor = Loader.Core.GetAmbient(0, Interval.Forever._IInterval).ToArray(); babylonScene.gravity = maxScene.RootNode._Node.GetVector3Property("babylonjs_gravity"); // Cameras BabylonCamera mainCamera = null; RaiseMessage("Exporting cameras"); foreach (var cameraNode in maxScene.NodesListBySuperClass(SuperClassID.Camera)) { var babylonCamera = ExportCamera(cameraNode, babylonScene); if (mainCamera == null) { mainCamera = babylonCamera; babylonScene.activeCameraID = mainCamera.id; RaiseMessage("Active camera set to " + mainCamera.name, true, true); } } if (mainCamera == null) { RaiseWarning("No camera defined", true); } // Fog for (var index = 0; index < Loader.Core.NumAtmospheric; index++) { var atmospheric = Loader.Core.GetAtmospheric(index); if (atmospheric.Active(0) && atmospheric.ClassName == "Fog") { RaiseMessage("Exporting fog"); var reference = atmospheric.GetReference(0); var parameters = Animatable.CreateWrapper <ParameterBlock1>(reference); babylonScene.fogColor = (parameters["fog color"].Value as IColor).ToArray(); babylonScene.fogDensity = (float)parameters["density"].Value; babylonScene.fogMode = ((int)parameters["fog type"].Value) == 0 ? 3 : 1; if (mainCamera != null) { babylonScene.fogStart = mainCamera.minZ * (float)parameters["near %"].Value; babylonScene.fogEnd = mainCamera.maxZ * (float)parameters["far %"].Value; } } } // Meshes RaiseMessage("Exporting meshes"); foreach (var meshNode in maxScene.NodesListBySuperClass(SuperClassID.GeometricObject)) { ExportMesh(meshNode, babylonScene); } // Materials RaiseMessage("Exporting materials"); var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials foreach (var mat in matsToExport) { ExportMaterial(mat, babylonScene); } // Lights RaiseMessage("Exporting lights"); foreach (var lightNode in maxScene.NodesListBySuperClass(SuperClassID.Light)) { ExportLight(lightNode, babylonScene); } // Output babylonScene.Prepare(false); var jsonSerializer = JsonSerializer.Create(); var sb = new StringBuilder(); var sw = new StringWriter(sb, CultureInfo.InvariantCulture); using (var jsonWriter = new JsonTextWriterOptimized(sw)) { jsonWriter.Formatting = Formatting.None; jsonSerializer.Serialize(jsonWriter, babylonScene); } File.WriteAllText(outputFile, sb.ToString()); ReportProgressChanged(100); RaiseMessage("Exportation done"); }
public void Export(ExportParameters exportParameters) { // Check input text is valid var scaleFactorFloat = 1.0f; string scaleFactor = exportParameters.scaleFactor; try { scaleFactor = scaleFactor.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactor = scaleFactor.Replace(",", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactorFloat = float.Parse(scaleFactor); } catch { RaiseError("Scale factor is not a valid number."); return; } long quality = 0L; string txtQuality = exportParameters.txtQuality; try { quality = long.Parse(txtQuality); if (quality < 0 || quality > 100) { throw new Exception(); } } catch { RaiseError("Quality is not a valid number. It should be an integer between 0 and 100."); RaiseError("This parameter set the quality of jpg compression."); return; } this.exportParameters = exportParameters; var gameConversionManger = Loader.Global.ConversionManager; gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d; var gameScene = Loader.Global.IGameInterface; if (exportParameters.exportNode == null) { gameScene.InitialiseIGame(false); } else { gameScene.InitialiseIGame(exportParameters.exportNode, true); } gameScene.SetStaticFrame(0); MaxSceneFileName = gameScene.SceneFileName; IsCancelled = false; string fileExportString = exportParameters.exportNode != null ? $"{exportParameters.exportNode.NodeName} | {exportParameters.outputPath}" : exportParameters.outputPath; RaiseMessage($"Exportation started: {fileExportString}", Color.Blue); ReportProgressChanged(0); string tempOutputDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string outputDirectory = Path.GetDirectoryName(exportParameters.outputPath); string outputFileName = Path.GetFileName(exportParameters.outputPath); // Check directory exists if (!Directory.Exists(outputDirectory)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } Directory.CreateDirectory(tempOutputDirectory); var outputBabylonDirectory = tempOutputDirectory; // Force output file extension to be babylon outputFileName = Path.ChangeExtension(outputFileName, "babylon"); var babylonScene = new BabylonScene(outputBabylonDirectory); var rawScene = Loader.Core.RootNode; var watch = new Stopwatch(); watch.Start(); string outputFormat = exportParameters.outputFormat; isBabylonExported = outputFormat == "babylon" || outputFormat == "binary babylon"; isGltfExported = outputFormat == "gltf" || outputFormat == "glb"; // Get scene parameters optimizeAnimations = !Loader.Core.RootNode.GetBoolProperty("babylonjs_donotoptimizeanimations"); exportNonAnimated = Loader.Core.RootNode.GetBoolProperty("babylonjs_animgroup_exportnonanimated"); // Save scene if (exportParameters.autoSave3dsMaxFile) { RaiseMessage("Saving 3ds max file"); var forceSave = Loader.Core.FileSave; callerForm?.BringToFront(); } // Producer babylonScene.producer = new BabylonProducer { name = "3dsmax", #if MAX2019 version = "2019", #elif MAX2018 version = "2018", #elif MAX2017 version = "2017", #else version = Loader.Core.ProductVersion.ToString(), #endif exporter_version = exporterVersion, file = outputFileName }; // 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); if (Loader.Core.UseEnvironmentMap && Loader.Core.EnvironmentMap != null) { // Environment texture var environmentMap = Loader.Core.EnvironmentMap; // Copy image file to output if necessary var babylonTexture = ExportEnvironmnentTexture(environmentMap, babylonScene); if (babylonTexture != null) { babylonScene.environmentTexture = babylonTexture.name; // Skybox babylonScene.createDefaultSkybox = rawScene.GetBoolProperty("babylonjs_createDefaultSkybox"); babylonScene.skyboxBlurLevel = rawScene.GetFloatProperty("babylonjs_skyboxBlurLevel"); } } // 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); if (isBabylonExported) { try { File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true); } catch { } } } // Root nodes RaiseMessage("Exporting nodes"); HashSet <IIGameNode> maxRootNodes = getRootNodes(gameScene); var progressionStep = 80.0f / maxRootNodes.Count; var progression = 10.0f; ReportProgressChanged((int)progression); referencedMaterials.Clear(); Tools.guids.Clear(); // Reseting is optionnal. It makes each morph target manager export starts from id = 0. BabylonMorphTargetManager.Reset(); foreach (var maxRootNode in maxRootNodes) { BabylonNode node = exportNodeRec(maxRootNode, babylonScene, gameScene); // if we're exporting from a specific node, reset the pivot to {0,0,0} if (node != null && exportParameters.exportNode != null) { SetNodePosition(ref node, ref babylonScene, new float[] { 0, 0, 0 }); } progression += progressionStep; ReportProgressChanged((int)progression); CheckCancelled(); } ; RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // In 3DS Max the default camera look down (in the -z direction for the 3DS Max reference (+y for babylon)) // In Babylon the default camera look to the horizon (in the +z direction for the babylon reference) // In glTF the default camera look to the horizon (in the +Z direction for glTF reference) RaiseMessage("Update camera rotation and position", 1); for (int index = 0; index < babylonScene.CamerasList.Count; index++) { BabylonCamera camera = babylonScene.CamerasList[index]; FixCamera(ref camera, ref babylonScene); } // Light for glTF if (isGltfExported) { RaiseMessage("Update light rotation for glTF export", 1); for (int index = 0; index < babylonScene.LightsList.Count; index++) { BabylonNode light = babylonScene.LightsList[index]; FixNodeRotation(ref light, ref babylonScene, -Math.PI / 2); } } // Main camera BabylonCamera babylonMainCamera = null; ICameraObject maxMainCameraObject = null; if (babylonMainCamera == null && babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); // Retreive camera node with same GUID var maxCameraNodesAsTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera); var maxCameraNodes = TabToList(maxCameraNodesAsTab); var maxMainCameraNode = maxCameraNodes.Find(_camera => _camera.MaxNode.GetGuid().ToString() == babylonMainCamera.id); maxMainCameraObject = (maxMainCameraNode.MaxNode.ObjectRef as ICameraObject); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light bool addDefaultLight = rawScene.GetBoolProperty("babylonjs_addDefaultLight", 1); if (addDefaultLight && 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 lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } if (scaleFactorFloat != 1.0f) { RaiseMessage("A root node is added for scaling", 1); // Create root node for scaling BabylonMesh rootNode = new BabylonMesh { name = "root", id = Guid.NewGuid().ToString() }; rootNode.isDummy = true; float rootNodeScale = scaleFactorFloat; rootNode.scaling = new float[3] { rootNodeScale, rootNodeScale, rootNodeScale }; if (ExportQuaternionsInsteadOfEulers) { rootNode.rotationQuaternion = new float[] { 0, 0, 0, 1 }; } else { rootNode.rotation = new float[] { 0, 0, 0 }; } // Update all top nodes var babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode babylonNode in babylonNodes) { if (babylonNode.parentId == null) { babylonNode.parentId = rootNode.id; } } // Store root node babylonScene.MeshesList.Add(rootNode); } // Materials if (exportParameters.exportMaterials) { 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); } else { RaiseMessage("Skipping material export."); } // 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 (babylonMainCamera != null) { babylonScene.fogStart = maxMainCameraObject.GetEnvRange(0, 0, Tools.Forever); babylonScene.fogEnd = maxMainCameraObject.GetEnvRange(0, 1, Tools.Forever); } } } // Skeletons if (skins.Count > 0) { RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // Animation group if (isBabylonExported) { RaiseMessage("Export animation groups"); // add animation groups to the scene babylonScene.animationGroups = ExportAnimationGroups(babylonScene); // if there is animationGroup, then remove animations from nodes if (babylonScene.animationGroups.Count > 0) { foreach (BabylonNode node in babylonScene.MeshesList) { node.animations = null; } foreach (BabylonNode node in babylonScene.LightsList) { node.animations = null; } foreach (BabylonNode node in babylonScene.CamerasList) { node.animations = null; } foreach (BabylonSkeleton skel in babylonScene.SkeletonsList) { foreach (BabylonBone bone in skel.bones) { bone.animation = null; } } } } // Output babylonScene.Prepare(false, false); if (isBabylonExported) { RaiseMessage("Saving to output file"); var outputFile = Path.Combine(outputBabylonDirectory, outputFileName); var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings()); var sb = new StringBuilder(); var sw = new StringWriter(sb, CultureInfo.InvariantCulture); using (var jsonWriter = new JsonTextWriterOptimized(sw)) { jsonWriter.Formatting = Formatting.None; jsonSerializer.Serialize(jsonWriter, babylonScene); } File.WriteAllText(outputFile, sb.ToString()); if (exportParameters.generateManifest) { File.WriteAllText(outputFile + ".manifest", "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}"); } // Binary if (outputFormat == "binary babylon") { RaiseMessage("Generating binary files"); BabylonFileConverter.BinaryConverter.Convert(outputFile, outputBabylonDirectory + "\\Binary", message => RaiseMessage(message, 1), error => RaiseError(error, 1)); } } ReportProgressChanged(100); // Export glTF if (isGltfExported) { bool generateBinary = outputFormat == "glb"; ExportGltf(babylonScene, tempOutputDirectory, outputFileName, generateBinary); } // Move files to output directory var filePaths = Directory.GetFiles(tempOutputDirectory); if (outputFormat == "binary babylon") { var tempBinaryOutputDirectory = Path.Combine(tempOutputDirectory, "Binary"); var binaryFilePaths = Directory.GetFiles(tempBinaryOutputDirectory); foreach (var filePath in binaryFilePaths) { if (filePath.EndsWith(".binary.babylon")) { var file = Path.GetFileName(filePath); var tempFilePath = Path.Combine(tempBinaryOutputDirectory, file); var outputFile = Path.Combine(outputDirectory, file); moveFileToOutputDirectory(tempFilePath, outputFile, exportParameters); } else if (filePath.EndsWith(".babylonbinarymeshdata")) { var file = Path.GetFileName(filePath); var tempFilePath = Path.Combine(tempBinaryOutputDirectory, file); var outputFile = Path.Combine(outputDirectory, file); moveFileToOutputDirectory(tempFilePath, outputFile, exportParameters); } } } if (outputFormat == "glb") { foreach (var file_path in filePaths) { if (Path.GetExtension(file_path) == ".glb") { var file = Path.GetFileName(file_path); var tempFilePath = Path.Combine(tempOutputDirectory, file); var outputFile = Path.Combine(outputDirectory, file); moveFileToOutputDirectory(tempFilePath, outputFile, exportParameters); break; } } } else { foreach (var filePath in filePaths) { var file = Path.GetFileName(filePath); var outputPath = Path.Combine(outputDirectory, file); var tempFilePath = Path.Combine(tempOutputDirectory, file); moveFileToOutputDirectory(tempFilePath, outputPath, exportParameters); } } Directory.Delete(tempOutputDirectory, true); watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s: {1}", watch.ElapsedMilliseconds / 1000.0, fileExportString), Color.Blue); }
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; alreadyExportedTextures.Clear(); 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); // 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 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); } } // 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); }
/// <summary> /// Export to file /// </summary> /// <param name="outputDirectory">The directory to store the generated files</param> /// <param name="outputFileName">The filename to use for the generated files</param> /// <param name="outputFormat">The format to use for the generated files</param> /// <param name="generateManifest">Specifies if a manifest file should be generated</param> /// <param name="onlySelected">Specifies if only the selected objects should be exported</param> /// <param name="autoSaveMayaFile">Specifies if the Maya scene should be auto-saved</param> /// <param name="exportHiddenObjects">Specifies if hidden objects should be exported</param> /// <param name="copyTexturesToOutput">Specifies if textures should be copied to the output directory</param> /// <param name="optimizeVertices">Specifies if vertices should be optimized on export</param> /// <param name="exportTangents">Specifies if tangents should be exported</param> /// <param name="scaleFactor">Scales the scene by this factor</param> /// <param name="exportSkin">Specifies if skins should be exported</param> /// <param name="quality">The texture quality</param> /// <param name="dracoCompression">Specifies if draco compression should be used</param> /// <param name="exportMorphNormal">Specifies if normals should be exported for morph targets</param> /// <param name="exportMorphTangent">Specifies if tangents should be exported for morph targets</param> /// <param name="exportKHRLightsPunctual">Specifies if the KHR_lights_punctual extension should be enabled</param> /// <param name="exportKHRTextureTransform">Specifies if the KHR_texture_transform extension should be enabled</param> /// <param name="bakeAnimationFrames">Specifies if animations should be exporting keyframes directly or should manually bake out animations frame by frame</param> public void Export(ExportParameters exportParameters) { this.exportParameters = exportParameters; // Check if the animation is running MGlobal.executeCommand("play -q - state", out int isPlayed); if (isPlayed == 1) { RaiseError("Stop the animation before exporting."); return; } RaiseMessage("Export started", Color.Blue); var progression = 0.0f; ReportProgressChanged(progression); // Store export options this.isBabylonExported = exportParameters.outputFormat == "babylon" || exportParameters.outputFormat == "binary babylon"; var outputBabylonDirectory = Path.GetDirectoryName(exportParameters.outputPath); // Check directory exists if (!Directory.Exists(outputBabylonDirectory)) { RaiseError("Export stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); var babylonScene = new BabylonScene(outputBabylonDirectory); // Save scene if (exportParameters.autoSaveSceneFile) { RaiseMessage("Saving Maya file"); // Query expand file name string fileName = MGlobal.executeCommandStringResult($@"file -q -exn;"); // If scene has already been saved previously if (fileName.EndsWith(".ma") || fileName.EndsWith(".mb")) { // Name is already specified and this line will not fail MFileIO.save(); } else { // Open SaveAs dialog window MGlobal.executeCommand($@"fileDialog2;"); } } // Force output file extension to be babylon var outputFileName = Path.ChangeExtension(Path.GetFileName(exportParameters.outputPath), "babylon"); // Store selected nodes MSelectionList selectedNodes = new MSelectionList(); MGlobal.getActiveSelectionList(selectedNodes); selectedNodeFullPaths = new List <string>(); MItSelectionList mItSelectionList = new MItSelectionList(selectedNodes); while (!mItSelectionList.isDone) { MDagPath mDagPath = new MDagPath(); try { mItSelectionList.getDagPath(mDagPath); selectedNodeFullPaths.Add(mDagPath.fullPathName); } catch { // selected object is not a DAG object // fail silently } mItSelectionList.next(); } if (selectedNodeFullPaths.Count > 0) { RaiseMessage("Selected nodes full path"); foreach (string selectedNodeFullPath in selectedNodeFullPaths) { RaiseMessage(selectedNodeFullPath, 1); } } // Producer babylonScene.producer = new BabylonProducer { name = "Maya", version = "2018", exporter_version = exporterVersion, file = outputFileName }; // Global babylonScene.autoClear = true; // TODO - Retreive colors from Maya //babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); //babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); babylonScene.TimelineStartFrame = Loader.GetMinTime(); babylonScene.TimelineEndFrame = Loader.GetMaxTime(); babylonScene.TimelineFramesPerSecond = Loader.GetFPS(); // TODO - Add custom properties _exportQuaternionsInsteadOfEulers = true; PrintDAG(true); PrintDAG(false); // Store the current frame. It can be change to find a proper one for the node/bone export double currentTime = Loader.GetCurrentTime(); // -------------------- // ------ Nodes ------- // -------------------- RaiseMessage("Exporting nodes"); // It makes each morph target manager export starts from id = 0. BabylonMorphTargetManager.Reset(); // Clear materials referencedMaterials.Clear(); multiMaterials.Clear(); // Get all nodes var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kTransform); List <MDagPath> nodes = new List <MDagPath>(); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); // Check if one of its descendant (direct or not) is a mesh/camera/light/locator if (isNodeRelevantToExportRec(mDagPath) // Ensure it's not one of the default cameras used as viewports in Maya && defaultCameraNames.Contains(mDagPath.partialPathName) == false) { nodes.Add(mDagPath); } else { // Skip descendants dagIterator.prune(); } dagIterator.next(); } // Export all nodes var progressionStep = 100.0f / nodes.Count; foreach (MDagPath mDagPath in nodes) { BabylonNode babylonNode = null; try { switch (getApiTypeOfDirectDescendants(mDagPath)) { case MFn.Type.kMesh: babylonNode = ExportMesh(mDagPath, babylonScene); break; case MFn.Type.kCamera: babylonNode = ExportCamera(mDagPath, babylonScene); break; case MFn.Type.kLight: // Lights api type are actually kPointLight, kSpotLight... babylonNode = ExportLight(mDagPath, babylonScene); break; case MFn.Type.kLocator: // Camera target babylonNode = ExportDummy(mDagPath, babylonScene); break; } } catch (Exception e) { this.RaiseWarning(String.Format("Exception raised during export. Node will be exported as dummy node. \r\nMessage: \r\n{0} \r\n{1}", e.Message, e.InnerException), 2); } // If node is not exported successfully if (babylonNode == null) { // Create a dummy (empty mesh) babylonNode = ExportDummy(mDagPath, babylonScene); } ; // Update progress bar progression += progressionStep; ReportProgressChanged(progression); CheckCancelled(); } RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // if nothing is enlightened, exclude all meshes foreach (BabylonLight light in babylonScene.LightsList) { if (light.includedOnlyMeshesIds.Length == 0) { light.excludedMeshesIds = babylonScene.MeshesList.Select(m => m.id).ToArray(); } } /* * Switch coordinate system at global level * * Add a root node with negative scaling * Pros - It's safer to use a root node * Cons - It's cleaner to switch at object level (as it is done now) * Use root node method when you want to be 100% sure of the output * Don't forget to also inverse winding order of mesh indices */ //// Switch from right to left handed coordinate system //MUuid mUuid = new MUuid(); //mUuid.generate(); //var rootNode = new BabylonMesh //{ // name = "root", // id = mUuid.asString(), // scaling = new float[] { 1, 1, -1 } //}; //foreach(var babylonMesh in babylonScene.MeshesList) //{ // // Add root meshes as child to root node // if (babylonMesh.parentId == null) // { // babylonMesh.parentId = rootNode.id; // } //} //babylonScene.MeshesList.Add(rootNode); // Main camera BabylonCamera babylonMainCamera = null; if (babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light if (!exportParameters.pbrNoLight && babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default ambient light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } var sceneScaleFactor = exportParameters.scaleFactor; if (exportParameters.scaleFactor != 1.0f) { RaiseMessage(String.Format("A root node is added to globally scale the scene by {0}", sceneScaleFactor), 1); // Create root node for scaling BabylonMesh rootNode = new BabylonMesh { name = "root", id = Tools.GenerateUUID() }; rootNode.isDummy = true; float rootNodeScale = sceneScaleFactor; rootNode.scaling = new float[3] { rootNodeScale, rootNodeScale, rootNodeScale }; if (ExportQuaternionsInsteadOfEulers) { rootNode.rotationQuaternion = new float[] { 0, 0, 0, 1 }; } else { rootNode.rotation = new float[] { 0, 0, 0 }; } // Update all top nodes var babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode babylonNode in babylonNodes) { if (babylonNode.parentId == null) { babylonNode.parentId = rootNode.id; } } // Store root node babylonScene.MeshesList.Add(rootNode); } // -------------------- // ----- Materials ---- // -------------------- RaiseMessage("Exporting materials"); GenerateMaterialDuplicationDatas(babylonScene); foreach (var mat in referencedMaterials) { ExportMaterial(mat, babylonScene, exportParameters.pbrFull); CheckCancelled(); } foreach (var mat in multiMaterials) { ExportMultiMaterial(mat.Key, mat.Value, babylonScene, exportParameters.pbrFull); CheckCancelled(); } UpdateMeshesMaterialId(babylonScene); RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Export skeletons if (exportParameters.exportSkins && skins.Count > 0) { progressSkin = 0; progressSkinStep = 100 / skins.Count; ReportProgressChanged(progressSkin); RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // set back the frame Loader.SetCurrentTime(currentTime); // ---------------------------- // ----- Animation groups ----- // ---------------------------- RaiseMessage("Export animation groups"); // add animation groups to the scene babylonScene.animationGroups = ExportAnimationGroups(babylonScene); if (isBabylonExported) { // if we are exporting to .Babylon then remove then remove animations from nodes if there are animation groups. if (babylonScene.animationGroups.Count > 0) { // add animations of each nodes in the animGroup List <BabylonNode> babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode node in babylonNodes) { node.animations = null; } foreach (BabylonSkeleton skel in babylonScene.SkeletonsList) { foreach (BabylonBone bone in skel.bones) { bone.animation = null; } } } // setup a default skybox for the scene for .Babylon export. var sourcePath = exportParameters.pbrEnvironment; if (!string.IsNullOrEmpty(sourcePath)) { babylonScene.createDefaultSkybox = exportParameters.createDefaultSkybox; var fileName = Path.GetFileName(sourcePath); // Allow only dds file format if (!fileName.EndsWith(".dds")) { RaiseWarning("Failed to export defauenvironment texture: only .dds format is supported."); } else { RaiseMessage($"texture id = Max_Babylon_Default_Environment"); babylonScene.environmentTexture = fileName; if (exportParameters.writeTextures) { try { var destPath = Path.Combine(babylonScene.OutputPath, fileName); if (File.Exists(sourcePath) && sourcePath != destPath) { File.Copy(sourcePath, destPath, true); } } catch { // silently fails RaiseMessage($"Fail to export the default env texture", 3); } } } } } // Output babylonScene.Prepare(false, false); if (isBabylonExported) { Write(babylonScene, outputBabylonDirectory, outputFileName, exportParameters.outputFormat, exportParameters.generateManifest); } ReportProgressChanged(100); // Export glTF if (exportParameters.outputFormat == "gltf" || exportParameters.outputFormat == "glb") { bool generateBinary = exportParameters.outputFormat == "glb"; GLTFExporter gltfExporter = new GLTFExporter(); gltfExporter.ExportGltf(this.exportParameters, babylonScene, outputBabylonDirectory, outputFileName, generateBinary, this); } watch.Stop(); RaiseMessage(string.Format("Export done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
public void Export(string outputDirectory, string outputFileName, string outputFormat, bool generateManifest, bool onlySelected, bool autoSaveMayaFile, bool exportHiddenObjects, bool copyTexturesToOutput, bool optimizeVertices, bool exportTangents, string scaleFactor, bool exportSkin) { // Chekc if the animation is running MGlobal.executeCommand("play -q - state", out int isPlayed); if (isPlayed == 1) { RaiseError("Stop the animation before exporting."); return; } // Check input text is valid var scaleFactorFloat = 1.0f; try { scaleFactor = scaleFactor.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactor = scaleFactor.Replace(",", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator); scaleFactorFloat = float.Parse(scaleFactor); } catch { RaiseError("Scale factor is not a valid number."); return; } RaiseMessage("Exportation started", Color.Blue); var progression = 0.0f; ReportProgressChanged(progression); // Store export options _onlySelected = onlySelected; _exportHiddenObjects = exportHiddenObjects; _optimizeVertices = optimizeVertices; _exportTangents = exportTangents; CopyTexturesToOutput = copyTexturesToOutput; isBabylonExported = outputFormat == "babylon" || outputFormat == "binary babylon"; _exportSkin = exportSkin; // Check directory exists if (!Directory.Exists(outputDirectory)) { RaiseError("Exportation stopped: Output folder does not exist"); ReportProgressChanged(100); return; } var watch = new Stopwatch(); watch.Start(); var outputBabylonDirectory = outputDirectory; var babylonScene = new BabylonScene(outputBabylonDirectory); // Save scene if (autoSaveMayaFile) { RaiseMessage("Saving Maya file"); // Query expand file name string fileName = MGlobal.executeCommandStringResult($@"file -q -exn;"); // If scene has already been saved previously if (fileName.EndsWith(".ma") || fileName.EndsWith(".mb")) { // Name is already specified and this line will not fail MFileIO.save(); } else { // Open SaveAs dialog window MGlobal.executeCommand($@"fileDialog2;"); } } // Force output file extension to be babylon outputFileName = Path.ChangeExtension(outputFileName, "babylon"); // Store selected nodes MSelectionList selectedNodes = new MSelectionList(); MGlobal.getActiveSelectionList(selectedNodes); selectedNodeFullPaths = new List <string>(); MItSelectionList mItSelectionList = new MItSelectionList(selectedNodes); while (!mItSelectionList.isDone) { MDagPath mDagPath = new MDagPath(); try { mItSelectionList.getDagPath(mDagPath); selectedNodeFullPaths.Add(mDagPath.fullPathName); } catch { // selected object is not a DAG object // fail silently } mItSelectionList.next(); } if (selectedNodeFullPaths.Count > 0) { RaiseMessage("Selected nodes full path"); foreach (string selectedNodeFullPath in selectedNodeFullPaths) { RaiseMessage(selectedNodeFullPath, 1); } } // Producer babylonScene.producer = new BabylonProducer { name = "Maya", version = "2018", exporter_version = exporterVersion, file = outputFileName }; // Global babylonScene.autoClear = true; // TODO - Retreive colors from Maya //babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray(); //babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray(); // TODO - Add custom properties _exportQuaternionsInsteadOfEulers = true; PrintDAG(true); PrintDAG(false); // -------------------- // ------ Nodes ------- // -------------------- RaiseMessage("Exporting nodes"); // Clear materials referencedMaterials.Clear(); multiMaterials.Clear(); // Get all nodes var dagIterator = new MItDag(MItDag.TraversalType.kDepthFirst, MFn.Type.kTransform); List <MDagPath> nodes = new List <MDagPath>(); while (!dagIterator.isDone) { MDagPath mDagPath = new MDagPath(); dagIterator.getPath(mDagPath); // Check if one of its descendant (direct or not) is a mesh/camera/light/locator if (isNodeRelevantToExportRec(mDagPath) // Ensure it's not one of the default cameras used as viewports in Maya && defaultCameraNames.Contains(mDagPath.partialPathName) == false) { nodes.Add(mDagPath); } else { // Skip descendants dagIterator.prune(); } dagIterator.next(); } // Export all nodes var progressionStep = 100.0f / nodes.Count; foreach (MDagPath mDagPath in nodes) { BabylonNode babylonNode = null; switch (getApiTypeOfDirectDescendants(mDagPath)) { case MFn.Type.kMesh: babylonNode = ExportMesh(mDagPath, babylonScene); break; case MFn.Type.kCamera: babylonNode = ExportCamera(mDagPath, babylonScene); break; case MFn.Type.kLight: // Lights api type are actually kPointLight, kSpotLight... babylonNode = ExportLight(mDagPath, babylonScene); break; case MFn.Type.kLocator: // Camera target babylonNode = ExportDummy(mDagPath, babylonScene); break; } // If node is not exported successfully if (babylonNode == null) { // Create a dummy (empty mesh) babylonNode = ExportDummy(mDagPath, babylonScene); } ; // Update progress bar progression += progressionStep; ReportProgressChanged(progression); CheckCancelled(); } RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // if nothing is enlightened, exclude all meshes foreach (BabylonLight light in babylonScene.LightsList) { if (light.includedOnlyMeshesIds.Length == 0) { light.excludedMeshesIds = babylonScene.MeshesList.Select(m => m.id).ToArray(); } } /* * Switch coordinate system at global level * * Add a root node with negative scaling * Pros - It's safer to use a root node * Cons - It's cleaner to switch at object level (as it is done now) * Use root node method when you want to be 100% sure of the output * Don't forget to also inverse winding order of mesh indices */ //// Switch from right to left handed coordinate system //MUuid mUuid = new MUuid(); //mUuid.generate(); //var rootNode = new BabylonMesh //{ // name = "root", // id = mUuid.asString(), // scaling = new float[] { 1, 1, -1 } //}; //foreach(var babylonMesh in babylonScene.MeshesList) //{ // // Add root meshes as child to root node // if (babylonMesh.parentId == null) // { // babylonMesh.parentId = rootNode.id; // } //} //babylonScene.MeshesList.Add(rootNode); // Main camera BabylonCamera babylonMainCamera = null; if (babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light if (babylonScene.LightsList.Count == 0) { RaiseWarning("No light defined", 1); RaiseWarning("A default ambient light was added for your convenience", 1); ExportDefaultLight(babylonScene); } else { RaiseMessage(string.Format("Total lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } if (scaleFactorFloat != 1.0f) { RaiseMessage("A root node is added for scaling", 1); // Create root node for scaling BabylonMesh rootNode = new BabylonMesh { name = "root", id = Tools.GenerateUUID() }; rootNode.isDummy = true; float rootNodeScale = 1.0f / scaleFactorFloat; rootNode.scaling = new float[3] { rootNodeScale, rootNodeScale, rootNodeScale }; // Update all top nodes var babylonNodes = new List <BabylonNode>(); babylonNodes.AddRange(babylonScene.MeshesList); babylonNodes.AddRange(babylonScene.CamerasList); babylonNodes.AddRange(babylonScene.LightsList); foreach (BabylonNode babylonNode in babylonNodes) { if (babylonNode.parentId == null) { babylonNode.parentId = rootNode.id; } } // Store root node babylonScene.MeshesList.Add(rootNode); } // -------------------- // ----- Materials ---- // -------------------- RaiseMessage("Exporting materials"); GenerateMaterialDuplicationDatas(babylonScene); foreach (var mat in referencedMaterials) { ExportMaterial(mat, babylonScene); CheckCancelled(); } foreach (var mat in multiMaterials) { ExportMultiMaterial(mat.Key, mat.Value, babylonScene); CheckCancelled(); } UpdateMeshesMaterialId(babylonScene); RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1); // Export skeletons if (_exportSkin && skins.Count > 0) { progressSkin = 0; progressSkinStep = 100 / skins.Count; ReportProgressChanged(progressSkin); RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // Output babylonScene.Prepare(false, false); if (isBabylonExported) { Write(babylonScene, outputBabylonDirectory, outputFileName, outputFormat, generateManifest); } ReportProgressChanged(100); // Export glTF if (outputFormat == "gltf" || outputFormat == "glb") { bool generateBinary = outputFormat == "glb"; ExportGltf(babylonScene, outputDirectory, outputFileName, generateBinary); } watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
private BabylonCamera ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (IsCameraExportable(cameraNode) == false) { return(null); } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = cameraNode.NodeParent.MaxNode.GetGuid().ToString(); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Type babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); // Control babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); // Collisions babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Position / rotation var localTM = GetLocalTM(cameraNode, 0); var position = localTM.Translation; var rotation = localTM.Rotation; babylonCamera.position = new[] { position.X, position.Y, position.Z }; var rotationQuaternion = new BabylonQuaternion { X = rotation.X, Y = rotation.Y, Z = rotation.Z, W = -rotation.W }; if (ExportQuaternionsInsteadOfEulers) { babylonCamera.rotationQuaternion = rotationQuaternion.ToArray(); } else { babylonCamera.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } else { // TODO - Check if should be local or world var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = localTM.ExtractMatrix3().VectorTransform(vDir).Normalize; vDir = vDir.Add(position); babylonCamera.target = new[] { vDir.X, vDir.Y, vDir.Z }; } // Animations var animations = new List <BabylonAnimation>(); GeneratePositionAnimation(cameraNode, animations); if (target == null) { // Export rotation animation //GenerateRotationAnimation(cameraNode, animations); ExportVector3Animation("target", animations, key => { var wmCam = GetLocalTM(cameraNode, key); var positionCam = wmCam.Translation; var vDir = Loader.Global.Point3.Create(0, -1, 0); vDir = wmCam.ExtractMatrix3().VectorTransform(vDir).Normalize; vDir = vDir.Add(positionCam); return(new[] { vDir.X, vDir.Y, vDir.Z }); }); } // Animation temporary stored for gltf but not exported for babylon // TODO - Will cause an issue when externalizing the glTF export process var extraAnimations = new List <BabylonAnimation>(); // Do not check if node rotation properties are animated GenerateRotationAnimation(cameraNode, extraAnimations, true); babylonCamera.extraAnimations = extraAnimations; ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }
static void DumpCameras(NovaScene scene, BabylonScene babylonScene) { foreach (NovaCamera camera in scene.Cameras) { var babylonCamera = new BabylonCamera(); babylonScene.CamerasList.Add(babylonCamera); babylonCamera.name = camera.Name; babylonCamera.id = camera.ID.ToString(); babylonCamera.position = camera.Position.ToArray(); babylonCamera.rotation = camera.Rotation.ToArray(); babylonCamera.fov = camera.FOV; babylonCamera.minZ = camera.NearClip; babylonCamera.maxZ = camera.FarClip; babylonCamera.inertia = camera.Inertia; babylonCamera.speed = camera.Speed; babylonCamera.checkCollisions = camera.CheckCollisions; babylonCamera.applyGravity = camera.ApplyGravity; babylonCamera.ellipsoid = camera.EllipsoidVector.ToArray(); } if (scene.ActiveCamera != null) { babylonScene.activeCameraID = scene.ActiveCamera.ID.ToString(); } }
private GLTFCamera ExportCamera(BabylonCamera babylonCamera, GLTF gltf, GLTFNode gltfParentNode) { RaiseMessage("GLTFExporter.Camera | Export camera named: " + babylonCamera.name, 1); // -------------------------- // ---------- Node ---------- // -------------------------- RaiseMessage("GLTFExporter.Camera | Node", 2); // Node var gltfNode = new GLTFNode(); gltfNode.name = GetUniqueNodeName(babylonCamera.name); gltfNode.index = gltf.NodesList.Count; gltf.NodesList.Add(gltfNode); // Hierarchy if (gltfParentNode != null) { RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as child to " + gltfParentNode.name, 3); gltfParentNode.ChildrenList.Add(gltfNode.index); gltfNode.parent = gltfParentNode; } else { // It's a root node // Only root nodes are listed in a gltf scene RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as root node to scene", 3); gltf.scenes[0].NodesList.Add(gltfNode.index); } // Transform gltfNode.translation = babylonCamera.position; if (babylonCamera.rotationQuaternion != null) { gltfNode.rotation = babylonCamera.rotationQuaternion; } else { // Convert rotation vector to quaternion BabylonVector3 rotationVector3 = new BabylonVector3 { X = babylonCamera.rotation[0], Y = babylonCamera.rotation[1], Z = babylonCamera.rotation[2] }; gltfNode.rotation = rotationVector3.toQuaternion().ToArray(); } // No scaling defined for babylon camera. Use identity instead. gltfNode.scale = new float[3] { 1, 1, 1 }; // Switch coordinate system at object level gltfNode.translation[2] *= -1; gltfNode.rotation[0] *= -1; gltfNode.rotation[1] *= -1; // Animations ExportNodeAnimation(babylonCamera, gltf, gltfNode); // --- prints --- #region prints RaiseVerbose("GLTFExporter.Camera | babylonCamera data", 2); RaiseVerbose("GLTFExporter.Camera | babylonCamera.type=" + babylonCamera.type, 3); RaiseVerbose("GLTFExporter.Camera | babylonCamera.fov=" + babylonCamera.fov, 3); RaiseVerbose("GLTFExporter.Camera | babylonCamera.maxZ=" + babylonCamera.maxZ, 3); RaiseVerbose("GLTFExporter.Camera | babylonCamera.minZ=" + babylonCamera.minZ, 3); #endregion // -------------------------- // ------- gltfCamera ------- // -------------------------- RaiseMessage("GLTFExporter.Camera | create gltfCamera", 2); // Camera var gltfCamera = new GLTFCamera { name = babylonCamera.name }; gltfCamera.index = gltf.CamerasList.Count; gltf.CamerasList.Add(gltfCamera); gltfNode.camera = gltfCamera.index; gltfCamera.gltfNode = gltfNode; // Camera type switch (babylonCamera.mode) { case (BabylonCamera.CameraMode.ORTHOGRAPHIC_CAMERA): var gltfCameraOrthographic = new GLTFCameraOrthographic(); gltfCameraOrthographic.xmag = 1; // Do not bother about it - still mandatory gltfCameraOrthographic.ymag = 1; // Do not bother about it - still mandatory gltfCameraOrthographic.zfar = babylonCamera.maxZ; gltfCameraOrthographic.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.orthographic.ToString(); gltfCamera.orthographic = gltfCameraOrthographic; break; case (BabylonCamera.CameraMode.PERSPECTIVE_CAMERA): var gltfCameraPerspective = new GLTFCameraPerspective(); gltfCameraPerspective.aspectRatio = null; // Do not bother about it - use default glTF value gltfCameraPerspective.yfov = babylonCamera.fov; // Babylon camera fov mode is assumed to be vertical (FOVMODE_VERTICAL_FIXED) gltfCameraPerspective.zfar = babylonCamera.maxZ; gltfCameraPerspective.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.perspective.ToString(); gltfCamera.perspective = gltfCameraPerspective; break; default: RaiseError("GLTFExporter.Camera | camera mode not found"); break; } return(gltfCamera); }
private BabylonCamera ExportCamera(Node cameraNode, BabylonScene babylonScene) { var maxCamera = (cameraNode.Object as Camera)._Camera; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, true); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.GetGuid().ToString(); if (cameraNode.HasParent()) { babylonCamera.parentId = cameraNode.Parent.GetGuid().ToString(); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Interval.Forever._IInterval)); babylonCamera.minZ = maxCamera.GetEnvRange(0, 0, Interval.Forever._IInterval); babylonCamera.maxZ = maxCamera.GetEnvRange(0, 1, Interval.Forever._IInterval); if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Control babylonCamera.speed = cameraNode._Node.GetFloatProperty("babylonjs_speed"); babylonCamera.inertia = cameraNode._Node.GetFloatProperty("babylonjs_inertia"); // Collisions babylonCamera.checkCollisions = cameraNode._Node.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode._Node.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode._Node.GetVector3Property("babylonjs_ellipsoid"); // Position var wm = cameraNode.GetWorldMatrix(0, cameraNode.HasParent()); var position = wm.Trans; babylonCamera.position = position.ToArraySwitched(); // Target var target = cameraNode._Node.Target; if (target != null) { babylonCamera.lockedTargetId = target.GetGuid().ToString(); } else { var dir = wm.GetRow(2).MultiplyBy(-1); babylonCamera.target = position.Add(dir).ToArraySwitched(); } // Animations var animations = new List <BabylonAnimation>(); ExportVector3Animation("position", animations, key => { var worldMatrix = cameraNode.GetWorldMatrix(key, cameraNode.HasParent()); return(worldMatrix.Trans.ToArraySwitched()); }); ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov(maxCamera.GetFOV(key, Interval.Forever._IInterval)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode._Node.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode._Node.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode._Node.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode._Node.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }
private int AddParameterSamplerAnimation(BabylonCamera babylonCamera, GLTFAnimation gltfAnimation, GLTFExporter exporter, GLTF gltf, int startFrame, int endFrame) { var samplerList = gltfAnimation.SamplerList; // Combine babylon animations from .babylon file and cached ones var babylonAnimations = new List <BabylonAnimation>(); if (babylonCamera.animations != null) { IEnumerable <BabylonAnimation> extendedAnimations = babylonCamera.animations.Where(anim => anim.name == "fov animation"); babylonAnimations.AddRange(extendedAnimations); } if (babylonAnimations.Count > 0) { if (babylonAnimations.Count > 0) { exporter.logger.RaiseMessage("GLTFExporter.Animation | Export animations of node named: " + babylonCamera.name, 2); } foreach (BabylonAnimation babylonAnimation in babylonAnimations) { var babylonAnimationKeysInRange = babylonAnimation.keys.Where(key => key.frame >= startFrame && key.frame <= endFrame); if (babylonAnimationKeysInRange.Count() <= 0) { continue; } string target_path = babylonAnimation.property; // --- Input --- var accessorInput = exporter._createAndPopulateInput(gltf, babylonAnimation, startFrame, endFrame); if (accessorInput == null) { continue; } // --- Output --- GLTFAccessor accessorOutput = FlightSimAsoboPropertyAnimationExtension._createAccessorOfProperty(target_path, gltf); if (accessorOutput == null) { continue; } // Populate accessor int numKeys = 0; foreach (var babylonAnimationKey in babylonAnimationKeysInRange) { numKeys++; // copy data before changing it in case animation groups overlap float[] outputValues = new float[babylonAnimationKey.values.Length]; babylonAnimationKey.values.CopyTo(outputValues, 0); // Store values as bytes foreach (var outputValue in outputValues) { accessorOutput.bytesList.AddRange(BitConverter.GetBytes(outputValue)); } } ; accessorOutput.count = numKeys; if (accessorOutput.count == 0) { exporter.logger.RaiseWarning(String.Format("GLTFExporter.Animation | No frames to export in material animation \"{1}\" of node named \"{0}\". This will cause an error in the output gltf.", babylonCamera.name, babylonAnimation.name)); } // Animation sampler var gltfAnimationSampler = new GLTFAnimationSampler { input = accessorInput.index, output = accessorOutput.index }; gltfAnimationSampler.index = samplerList.Count; samplerList.Add(gltfAnimationSampler); } } else { return(-1); } return(samplerList.Count - 1); }
/// <summary> /// In 3DS Max the default camera look down (in the -z direction for the 3DS Max reference (+y for babylon)) /// In Babylon the default camera look to the horizon (in the +z direction for the babylon reference) /// So to correct this difference, this function apply a rotation to the camera and its first children. /// </summary> /// <param name="camera"></param> /// <param name="babylonScene">Use the exported babylon scene to get the final hierarchy</param> private void FixCamera(ref BabylonCamera camera, ref BabylonScene babylonScene) { string id = camera.id; IList <BabylonMesh> meshes = babylonScene.MeshesList.FindAll(mesh => mesh.parentId == null ? false : mesh.parentId.Equals(id)); RaiseMessage($"{camera.name}", 2); if (camera.target == null) { // fix the vue // Rotation around the axis X of PI / 2 in the indirect direction double angle = Math.PI / 2; if (camera.rotation != null) { camera.rotation[0] += (float)angle; } if (camera.rotationQuaternion != null) { BabylonQuaternion rotationQuaternion = FixCameraQuaternion(camera, angle); camera.rotationQuaternion = rotationQuaternion.ToArray(); camera.rotation = rotationQuaternion.toEulerAngles().ToArray(); } // animation List <BabylonAnimation> animations = new List <BabylonAnimation>(camera.animations); BabylonAnimation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } else // if the camera has a lockedTargetId, it is the extraAnimations that stores the rotation animation { if (camera.extraAnimations != null) { List <BabylonAnimation> extraAnimations = new List <BabylonAnimation>(camera.extraAnimations); animationRotationQuaternion = extraAnimations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixCameraQuaternion(key.values, angle); } } } } // fix direct children // Rotation around the axis X of -PI / 2 in the direct direction angle = -Math.PI / 2; foreach (var mesh in meshes) { RaiseVerbose($"{mesh.name}", 3); mesh.position = new float[] { mesh.position[0], mesh.position[2], -mesh.position[1] }; // Add a rotation of PI/2 axis X in direct direction if (mesh.rotationQuaternion != null) { // Rotation around the axis X of -PI / 2 in the direct direction BabylonQuaternion quaternion = FixChildQuaternion(mesh, angle); mesh.rotationQuaternion = quaternion.ToArray(); } if (mesh.rotation != null) { mesh.rotation[0] += (float)angle; } // Animations animations = new List <BabylonAnimation>(mesh.animations); // Position BabylonAnimation animationPosition = animations.Find(animation => animation.property.Equals("position")); if (animationPosition != null) { foreach (BabylonAnimationKey key in animationPosition.keys) { key.values = new float[] { key.values[0], key.values[2], -key.values[1] }; } } // Rotation animationRotationQuaternion = animations.Find(animation => animation.property.Equals("rotationQuaternion")); if (animationRotationQuaternion != null) { foreach (BabylonAnimationKey key in animationRotationQuaternion.keys) { key.values = FixChildQuaternion(key.values, angle); } } } } }
public async Task ExportAsync(string outputFile, string outputFormat, bool generateManifest, bool onlySelected, 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; // Force output file extension to be babylon outputFile = Path.ChangeExtension(outputFile, "babylon"); 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 if (AutoSave3dsMaxFile) { RaiseMessage("Saving 3ds max file"); var forceSave = Loader.Core.FileSave; callerForm?.BringToFront(); } // Producer babylonScene.producer = new BabylonProducer { name = "3dsmax", #if MAX2017 version = "2017", #else version = Loader.Core.ProductVersion.ToString(), #endif exporter_version = "0.4.5", file = Path.GetFileName(outputFile) }; // 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); if (Loader.Core.UseEnvironmentMap && Loader.Core.EnvironmentMap != null) { // Environment texture var environmentMap = Loader.Core.EnvironmentMap; // Copy image file to output if necessary var babylonTexture = ExportTexture(environmentMap, 1.0f, babylonScene, true); babylonScene.environmentTexture = babylonTexture.name; // Skybox babylonScene.createDefaultSkybox = rawScene.GetBoolProperty("babylonjs_createDefaultSkybox"); babylonScene.skyboxBlurLevel = rawScene.GetFloatProperty("babylonjs_skyboxBlurLevel"); } // 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 { } } // Root nodes RaiseMessage("Exporting nodes"); HashSet <IIGameNode> maxRootNodes = getRootNodes(gameScene); var progressionStep = 80.0f / maxRootNodes.Count; var progression = 10.0f; ReportProgressChanged((int)progression); referencedMaterials.Clear(); // Reseting is optionnal. It makes each morph target manager export starts from id = 0. BabylonMorphTargetManager.Reset(); foreach (var maxRootNode in maxRootNodes) { exportNodeRec(maxRootNode, babylonScene, gameScene); progression += progressionStep; ReportProgressChanged((int)progression); CheckCancelled(); } ; RaiseMessage(string.Format("Total meshes: {0}", babylonScene.MeshesList.Count), Color.Gray, 1); // Main camera BabylonCamera babylonMainCamera = null; ICameraObject maxMainCameraObject = null; if (babylonMainCamera == null && babylonScene.CamerasList.Count > 0) { // Set first camera as main one babylonMainCamera = babylonScene.CamerasList[0]; babylonScene.activeCameraID = babylonMainCamera.id; RaiseMessage("Active camera set to " + babylonMainCamera.name, Color.Green, 1, true); // Retreive camera node with same GUID var maxCameraNodesAsTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera); var maxCameraNodes = TabToList(maxCameraNodesAsTab); var maxMainCameraNode = maxCameraNodes.Find(_camera => _camera.MaxNode.GetGuid().ToString() == babylonMainCamera.id); maxMainCameraObject = (maxMainCameraNode.MaxNode.ObjectRef as ICameraObject); } if (babylonMainCamera == null) { RaiseWarning("No camera defined", 1); } else { RaiseMessage(string.Format("Total cameras: {0}", babylonScene.CamerasList.Count), Color.Gray, 1); } // Default light 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 lights: {0}", babylonScene.LightsList.Count), Color.Gray, 1); } // 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); // 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 (babylonMainCamera != null) { babylonScene.fogStart = maxMainCameraObject.GetEnvRange(0, 0, Tools.Forever); babylonScene.fogEnd = maxMainCameraObject.GetEnvRange(0, 1, Tools.Forever); } } } // Skeletons if (skins.Count > 0) { RaiseMessage("Exporting skeletons"); foreach (var skin in skins) { ExportSkin(skin, babylonScene); } } // Actions babylonScene.actions = ExportNodeAction(gameScene.GetIGameNode(rawScene)); // Output babylonScene.Prepare(false, false); if (outputFormat == "babylon" || outputFormat == "binary babylon") { RaiseMessage("Saving to output file"); 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 (outputFormat == "binary babylon") { RaiseMessage("Generating binary files"); BabylonFileConverter.BinaryConverter.Convert(outputFile, Path.GetDirectoryName(outputFile) + "\\Binary", message => RaiseMessage(message, 1), error => RaiseError(error, 1)); } } ReportProgressChanged(100); // Export glTF if (outputFormat == "gltf" || outputFormat == "glb") { bool generateBinary = outputFormat == "glb"; ExportGltf(babylonScene, outputFile, generateBinary); } watch.Stop(); RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue); }
/// <summary> /// /// </summary> /// <param name="mDagPath">DAG path to the transform above camera</param> /// <param name="babylonScene"></param> /// <returns></returns> private BabylonNode ExportCamera(MDagPath mDagPath, BabylonScene babylonScene) { RaiseMessage(mDagPath.partialPathName, 1); // Transform above camera MFnTransform mFnTransform = new MFnTransform(mDagPath); // Camera direct child of the transform MFnCamera mFnCamera = null; for (uint i = 0; i < mFnTransform.childCount; i++) { MObject childObject = mFnTransform.child(i); if (childObject.apiType == MFn.Type.kCamera) { var _mFnCamera = new MFnCamera(childObject); if (!_mFnCamera.isIntermediateObject) { mFnCamera = _mFnCamera; } } } if (mFnCamera == null) { RaiseError("No camera found has child of " + mDagPath.fullPathName); return(null); } // --- prints --- #region prints RaiseVerbose("BabylonExporter.Camera | mFnCamera data", 2); RaiseVerbose("BabylonExporter.Camera | mFnCamera.eyePoint(MSpace.Space.kWorld).toString()=" + mFnCamera.eyePoint(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.viewDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.viewDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.upDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.upDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.rightDirection(MSpace.Space.kWorld).toString()=" + mFnCamera.rightDirection(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.centerOfInterestPoint(MSpace.Space.kWorld).toString()=" + mFnCamera.centerOfInterestPoint(MSpace.Space.kTransform).toString(), 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.centerOfInterest=" + mFnCamera.centerOfInterest, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.aspectRatio=" + mFnCamera.aspectRatio, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.horizontalFieldOfView=" + mFnCamera.horizontalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.verticalFieldOfView=" + mFnCamera.verticalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.horizontalFieldOfView / mFnCamera.verticalFieldOfView=" + mFnCamera.horizontalFieldOfView / mFnCamera.verticalFieldOfView, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.focalLength=" + mFnCamera.focalLength, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.nearFocusDistance=" + mFnCamera.nearFocusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.nearClippingPlane=" + mFnCamera.nearClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.unnormalizedNearClippingPlane=" + mFnCamera.unnormalizedNearClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.farFocusDistance=" + mFnCamera.farFocusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.farClippingPlane=" + mFnCamera.farClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.unnormalizedFarClippingPlane=" + mFnCamera.unnormalizedFarClippingPlane, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isClippingPlanes=" + mFnCamera.isClippingPlanes, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isIntermediateObject=" + mFnCamera.isIntermediateObject, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.focusDistance=" + mFnCamera.focusDistance, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isStereo=" + mFnCamera.isStereo, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.eyeOffset=" + mFnCamera.eyeOffset, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.shutterAngle=" + mFnCamera.shutterAngle, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.isDepthOfField=" + mFnCamera.isDepthOfField, 3); RaiseVerbose("BabylonExporter.Camera | mFnCamera.renderPanZoom=" + mFnCamera.renderPanZoom, 3); Print(mFnTransform, 2, "Print ExportCamera mFnTransform"); Print(mFnCamera, 2, "Print ExportCamera mFnCamera"); #endregion if (IsCameraExportable(mFnCamera, mDagPath) == false) { return(null); } var babylonCamera = new BabylonCamera { name = mFnTransform.name, id = mFnTransform.uuid().asString() }; // Hierarchy ExportHierarchy(babylonCamera, mFnTransform); // Position / rotation RaiseVerbose("BabylonExporter.Camera | ExportTransform", 2); float[] position = null; float[] rotationQuaternion = null; float[] rotation = null; float[] scaling = null; GetTransform(mFnTransform, ref position, ref rotationQuaternion, ref rotation, ref scaling); babylonCamera.position = position; if (_exportQuaternionsInsteadOfEulers) { babylonCamera.rotationQuaternion = rotationQuaternion; } babylonCamera.rotation = rotation; // Field of view of babylon is the vertical one babylonCamera.fov = (float)mFnCamera.verticalFieldOfView; // Clipping planes babylonCamera.minZ = (float)mFnCamera.nearClippingPlane; babylonCamera.maxZ = (float)mFnCamera.farClippingPlane; // Constraints on near clipping plane if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // TODO - Retreive from Maya //// Type //babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); //// Control //babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); //babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); //// Collisions //babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); //babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); //babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Target MFnTransform target = null; MObject cameraGroupObject = mFnCamera.findPlug("centerOfInterest").source.node; if (cameraGroupObject.apiType == MFn.Type.kLookAt) { MFnDependencyNode cameraGroup = new MFnDependencyNode(cameraGroupObject); // Retreive the camera aim transform MPlugArray connections = new MPlugArray(); cameraGroup.getConnections(connections); foreach (MPlug connection in connections) { if (connection.name.EndsWith("targetParentMatrix")) // ugly { MObject connectionSourceObject = connection.source.node; target = new MFnTransform(connectionSourceObject); break; } } } if (target != null) { babylonCamera.lockedTargetId = target.uuid().asString(); } //// TODO - Check if should be local or world //var vDir = new MVector(0, 0, -1); //var transformationMatrix = new MTransformationMatrix(mFnTransform.transformationMatrix); //vDir *= transformationMatrix.asMatrix(1); //vDir = vDir.Add(position); //babylonCamera.target = new[] { vDir.X, vDir.Y, vDir.Z }; // Animations if (target == null) { ExportNodeAnimation(babylonCamera, mFnTransform); } else { ExportNodeAnimationFrameByFrame(babylonCamera, mFnTransform); } babylonScene.CamerasList.Add(babylonCamera); RaiseMessage("BabylonExporter.Camera | done", 2); return(babylonCamera); }
private GLTFCamera ExportCamera(ref GLTFNode gltfNode, BabylonCamera babylonCamera, GLTF gltf, GLTFNode gltfParentNode) { logger.RaiseMessage("GLTFExporter.Camera | Export camera named: " + babylonCamera.name, 2); // --- prints --- #region prints logger.RaiseVerbose("GLTFExporter.Camera | babylonCamera data", 3); logger.RaiseVerbose("GLTFExporter.Camera | babylonCamera.type=" + babylonCamera.type, 4); logger.RaiseVerbose("GLTFExporter.Camera | babylonCamera.fov=" + babylonCamera.fov, 4); logger.RaiseVerbose("GLTFExporter.Camera | babylonCamera.maxZ=" + babylonCamera.maxZ, 4); logger.RaiseVerbose("GLTFExporter.Camera | babylonCamera.minZ=" + babylonCamera.minZ, 4); #endregion // -------------------------- // ------- gltfCamera ------- // -------------------------- logger.RaiseMessage("GLTFExporter.Camera | create gltfCamera", 3); // Camera var gltfCamera = new GLTFCamera { name = babylonCamera.name }; gltfCamera.index = gltf.CamerasList.Count; gltf.CamerasList.Add(gltfCamera); gltfNode.camera = gltfCamera.index; gltfCamera.gltfNode = gltfNode; // Camera type switch (babylonCamera.mode) { case (BabylonCamera.CameraMode.ORTHOGRAPHIC_CAMERA): var gltfCameraOrthographic = new GLTFCameraOrthographic(); gltfCameraOrthographic.xmag = 1; // Do not bother about it - still mandatory gltfCameraOrthographic.ymag = 1; // Do not bother about it - still mandatory gltfCameraOrthographic.zfar = babylonCamera.maxZ; gltfCameraOrthographic.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.orthographic.ToString(); gltfCamera.orthographic = gltfCameraOrthographic; break; case (BabylonCamera.CameraMode.PERSPECTIVE_CAMERA): var gltfCameraPerspective = new GLTFCameraPerspective(); gltfCameraPerspective.aspectRatio = null; // Do not bother about it - use default glTF value gltfCameraPerspective.yfov = babylonCamera.fov; // Babylon camera fov mode is assumed to be vertical (FOVMODE_VERTICAL_FIXED) gltfCameraPerspective.zfar = babylonCamera.maxZ; gltfCameraPerspective.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.perspective.ToString(); gltfCamera.perspective = gltfCameraPerspective; break; default: logger.RaiseError("GLTFExporter.Camera | camera mode not found"); break; } ExportGLTFExtension(babylonCamera, ref gltfCamera, gltf); return(gltfCamera); }
private BabylonCamera ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (IsCameraExportable(cameraNode) == false) { return(null); } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = cameraNode.NodeParent.MaxNode.GetGuid().ToString(); } // Export the custom attributes of this camera babylonCamera.metadata = ExportExtraAttributes(cameraNode, babylonScene); babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Type babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); // Control babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); // Collisions babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Position / rotation exportTransform(babylonCamera, cameraNode); // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } // Animations var animations = new List <BabylonAnimation>(); GeneratePositionAnimation(cameraNode, animations); if (target == null) { // Export rotation animation GenerateRotationAnimation(cameraNode, animations); } else { // Animation temporary stored for gltf but not exported for babylon // TODO - Will cause an issue when externalizing the glTF export process var extraAnimations = new List <BabylonAnimation>(); // Do not check if node rotation properties are animated GenerateRotationAnimation(cameraNode, extraAnimations, true); babylonCamera.extraAnimations = extraAnimations; } ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); return(babylonCamera); }
private void ExportCamera(IIGameScene scene, IIGameNode cameraNode, BabylonScene babylonScene) { if (cameraNode.MaxNode.GetBoolProperty("babylonjs_noexport")) { return; } var gameCamera = cameraNode.IGameObject.AsGameCamera(); var maxCamera = gameCamera.MaxObject as ICameraObject; var initialized = gameCamera.InitializeData; var babylonCamera = new BabylonCamera(); RaiseMessage(cameraNode.Name, 1); babylonCamera.name = cameraNode.Name; babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString(); if (cameraNode.NodeParent != null) { babylonCamera.parentId = GetParentID(cameraNode.NodeParent, babylonScene, scene); } babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever)); if (maxCamera.ManualClip == 1) { babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever); babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever); } else { babylonCamera.minZ = 0.1f; babylonCamera.maxZ = 10000.0f; } if (babylonCamera.minZ == 0.0f) { babylonCamera.minZ = 0.1f; } // Type babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera"); // Control babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f); babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f); // Collisions babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions"); babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity"); babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid"); // Position / rotation var localTM = cameraNode.GetObjectTM(0); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(0); localTM.MultiplyBy(parentWorld.Inverse); } var position = localTM.Translation; var rotation = localTM.Rotation; var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions"); babylonCamera.position = new[] { position.X, position.Y, position.Z }; if (exportQuaternions) { babylonCamera.rotationQuaternion = new[] { rotation.X, rotation.Y, rotation.Z, -rotation.W }; } else { babylonCamera.rotation = QuaternionToEulerAngles(rotation); } // Target var target = gameCamera.CameraTarget; if (target != null) { babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString(); } else { var dir = localTM.GetRow(3); babylonCamera.target = new [] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z }; } // Animations var animations = new List <BabylonAnimation>(); ExportVector3Animation("position", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; return(new [] { translation.X, translation.Y, translation.Z }); }); if (gameCamera.CameraTarget == null) { ExportVector3Animation("target", animations, key => { var tm = cameraNode.GetLocalTM(key); if (cameraNode.NodeParent != null) { var parentWorld = cameraNode.NodeParent.GetObjectTM(key); tm.MultiplyBy(parentWorld.Inverse); } var translation = tm.Translation; var dir = tm.GetRow(3); return(new float[] { translation.X - dir.X, translation.Y - dir.Y, translation.Z - dir.Z }); }); } ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) }); babylonCamera.animations = animations.ToArray(); if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate")) { babylonCamera.autoAnimate = true; babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from"); babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to"); babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop"); } babylonScene.CamerasList.Add(babylonCamera); }
// TODO - Test if ok with a gltf viewer working with custom camera (babylon loader/sandbox doesn't load them) private GLTFCamera ExportCamera(BabylonCamera babylonCamera, GLTF gltf, GLTFNode gltfParentNode) { RaiseMessage("GLTFExporter.Camera | Export camera named: " + babylonCamera.name, 1); // -------------------------- // ---------- Node ---------- // -------------------------- RaiseMessage("GLTFExporter.Camera | Node", 2); // Node var gltfNode = new GLTFNode(); gltfNode.name = babylonCamera.name; gltfNode.index = gltf.NodesList.Count; gltf.NodesList.Add(gltfNode); // Hierarchy if (gltfParentNode != null) { RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as child to " + gltfParentNode.name, 3); gltfParentNode.ChildrenList.Add(gltfNode.index); } else { // It's a root node // Only root nodes are listed in a gltf scene RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as root node to scene", 3); gltf.scenes[0].NodesList.Add(gltfNode.index); } // Transform gltfNode.translation = babylonCamera.position; // Switch from left to right handed coordinate system //gltfNode.translation[0] *= -1; if (babylonCamera.rotationQuaternion != null) { gltfNode.rotation = babylonCamera.rotationQuaternion; } else { // Convert rotation vector to quaternion BabylonVector3 rotationVector3 = new BabylonVector3 { X = babylonCamera.rotation[0], Y = babylonCamera.rotation[1], Z = babylonCamera.rotation[2] }; gltfNode.rotation = rotationVector3.toQuaternionGltf().ToArray(); } // No scaling defined for babylon camera. Use identity instead. gltfNode.scale = new float[3] { 1, 1, 1 }; // --- prints --- RaiseMessage("GLTFExporter.Camera | babylonCamera data", 2); RaiseMessage("GLTFExporter.Camera | babylonCamera.type=" + babylonCamera.type, 3); RaiseMessage("GLTFExporter.Camera | babylonCamera.fov=" + babylonCamera.fov, 3); RaiseMessage("GLTFExporter.Camera | babylonCamera.maxZ=" + babylonCamera.maxZ, 3); RaiseMessage("GLTFExporter.Camera | babylonCamera.minZ=" + babylonCamera.minZ, 3); // -------------------------- // ------- gltfCamera ------- // -------------------------- RaiseMessage("GLTFExporter.Camera | create gltfCamera", 2); // Camera var gltfCamera = new GLTFCamera { name = babylonCamera.name }; gltfCamera.index = gltf.CamerasList.Count; gltf.CamerasList.Add(gltfCamera); gltfNode.camera = gltfCamera.index; gltfCamera.gltfNode = gltfNode; // Camera type switch (babylonCamera.mode) { case (BabylonCamera.CameraMode.ORTHOGRAPHIC_CAMERA): var gltfCameraOrthographic = new GLTFCameraOrthographic(); gltfCameraOrthographic.xmag = 1; // TODO - How to retreive value from babylon? xmag:The floating-point horizontal magnification of the view gltfCameraOrthographic.ymag = 1; // TODO - How to retreive value from babylon? ymag:The floating-point vertical magnification of the view gltfCameraOrthographic.zfar = babylonCamera.maxZ; gltfCameraOrthographic.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.orthographic.ToString(); gltfCamera.orthographic = gltfCameraOrthographic; break; case (BabylonCamera.CameraMode.PERSPECTIVE_CAMERA): var gltfCameraPerspective = new GLTFCameraPerspective(); gltfCameraPerspective.aspectRatio = null; // 0.8f; // TODO - How to retreive value from babylon? The aspect ratio in babylon is computed based on the engine rather than set on a camera (aspectRatio = _gl.drawingBufferWidth / _gl.drawingBufferHeight) gltfCameraPerspective.yfov = babylonCamera.fov; // WARNING - Babylon camera fov mode is assumed to be vertical (FOVMODE_VERTICAL_FIXED) gltfCameraPerspective.zfar = babylonCamera.maxZ; gltfCameraPerspective.znear = babylonCamera.minZ; gltfCamera.type = GLTFCamera.CameraType.perspective.ToString(); gltfCamera.perspective = gltfCameraPerspective; break; default: RaiseError("GLTFExporter.Camera | camera mode not found"); break; } return(gltfCamera); }