コード例 #1
0
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            robotViewer1 = new RobotViewer();
            FolderBrowserDialog browser = new FolderBrowserDialog();

            if (browser.ShowDialog() == DialogResult.OK && browser.SelectedPath != null)
            {
                RigidNode_Base node = BXDJSkeleton.ReadSkeleton(browser.SelectedPath + @"\skeleton.bxdj");

                List <RigidNode_Base> nodes = node.ListAllNodes();

                List <BXDAMesh> meshes = new List <BXDAMesh>();

                foreach (RigidNode_Base n in nodes)
                {
                    BXDAMesh mesh = new BXDAMesh();
                    mesh.ReadFromFile(browser.SelectedPath + "\\" + n.ModelFileName);

                    if (!n.GUID.Equals(mesh.GUID))
                    {
                        MessageBox.Show(n.ModelFileName + " has been modified.", "Could not load mesh.");
                    }
                    meshes.Add(mesh);
                }
                robotViewer1.LoadModel(node, meshes);
                robotViewer1.FixLimits();
                robotViewer1.HighlightAll();

                Text = "Robot Viewer: " + browser.SelectedPath.Split(new char[] { '\\' }, System.StringSplitOptions.RemoveEmptyEntries)[browser.SelectedPath.Split(new char[] { '\\' }, System.StringSplitOptions.RemoveEmptyEntries).Length - 1];
            }
        }
コード例 #2
0
ファイル: WizardForm.cs プロジェクト: ezhangle/synthesis
        public WizardForm()
        {
            InitializeComponent();

            if (Utilities.GUI.SkeletonBase == null)
            {
                BXDJSkeleton.SetupFileNames(Utilities.GUI.SkeletonBase);
            }

            this.Resize += WizardForm_Resize;

            //Step 1: Define Wheels
            DefineWheelsPage defineWheelsPage = new DefineWheelsPage();

            defineWheelsPage.ActivateNext   += ActivateNext;
            defineWheelsPage.DeactivateNext += DeactivateNext;
            defineWheelsPage.SetEndEarly    += SetEndEarly;
            WizardPages.Add(defineWheelsPage, WizardNavigator.WizardNavigatorState.Clean | WizardNavigator.WizardNavigatorState.BackHidden);

            //Step 2: Define other moving parts
            DefineMovingPartsPage defineMovingPartsPage = new DefineMovingPartsPage();

            defineMovingPartsPage.ActivateNext   += ActivateNext;
            defineMovingPartsPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(defineMovingPartsPage, WizardNavigator.WizardNavigatorState.Clean | WizardNavigator.WizardNavigatorState.FinishEnabled);

            WizardPages.BeginWizard();
            WizardPages.FinishClicked += delegate()
            {
                WizardData.Instance.Apply();
                StandardAddInServer.Instance.PendingChanges = true;
                Close();
            };
        }
コード例 #3
0
    /// <summary>
    /// Saves the robot to the directory it was loaded from or the default directory
    /// </summary>
    /// <returns></returns>
    public bool RobotSave(bool silent = false)
    {
        try
        {
            if (!Directory.Exists(PluginSettings.GeneralSaveLocation + "\\" + RMeta.ActiveRobotName))
            {
                Directory.CreateDirectory(PluginSettings.GeneralSaveLocation + "\\" + RMeta.ActiveRobotName);
            }
            BXDJSkeleton.SetupFileNames(SkeletonBase);
            BXDJSkeleton.WriteSkeleton((RMeta.UseSettingsDir && RMeta.ActiveDir != null) ? RMeta.ActiveDir : PluginSettings.GeneralSaveLocation + "\\" + RMeta.ActiveRobotName + "\\skeleton.bxdj", SkeletonBase);
            for (int i = 0; i < Meshes.Count; i++)
            {
                Meshes[i].WriteToFile((RMeta.UseSettingsDir && RMeta.ActiveDir != null) ? RMeta.ActiveDir : PluginSettings.GeneralSaveLocation + "\\" + RMeta.ActiveRobotName + "\\node_" + i + ".bxda");
            }

            for (int i = 0; i < Meshes.Count; i++)
            {
                Meshes[i].WriteToFile((RMeta.UseSettingsDir && RMeta.ActiveDir != null) ? RMeta.ActiveDir : PluginSettings.GeneralSaveLocation + "\\" + RMeta.ActiveRobotName + "\\node_" + i + ".bxda");
            }
            if (!silent)
            {
                MessageBox.Show("Saved");
            }
            return(true);
        }
        catch (Exception e)
        {
            //TODO: Create a form that displays a simple error message with an option to expand it and view the exception info
            MessageBox.Show("Error saving robot: " + e.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return(false);
        }
    }
コード例 #4
0
    /// <summary>
    /// Saves the robot to the currently set robot directory.
    /// </summary>
    /// <param name="robotName"></param>
    public bool RobotSaveAs(NameRobotForm.NameMode mode = NameRobotForm.NameMode.SaveAs)
    {
        if (NameRobotForm.NameRobot(out string robotName, mode) == DialogResult.OK)
        {
            try
            {
                if (!Directory.Exists(PluginSettings.GeneralSaveLocation + "\\" + robotName))
                {
                    Directory.CreateDirectory(PluginSettings.GeneralSaveLocation + "\\" + robotName);
                }

                BXDJSkeleton.WriteSkeleton(PluginSettings.GeneralSaveLocation + "\\" + robotName + "\\skeleton.bxdj", SkeletonBase);

                for (int i = 0; i < Meshes.Count; i++)
                {
                    Meshes[i].WriteToFile(PluginSettings.GeneralSaveLocation + "\\" + robotName + "\\node_" + i + ".bxda");
                }

                MessageBox.Show("Saved");

                RMeta.UseSettingsDir  = true;
                RMeta.ActiveDir       = null;
                RMeta.ActiveRobotName = robotName;

                return(true);
            }
            catch (Exception e)
            {
                //TODO: Create a form that displays a simple error message with an option to expand it and view the exception info
                MessageBox.Show("Error saving robot: " + e.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }
        }
        return(false);
    }
コード例 #5
0
ファイル: PlayerIdentity.cs プロジェクト: ezhangle/synthesis
        /// <summary>
        /// Loads the selected robot file and reads its GUID.
        /// </summary>
        public void UpdateRobotGuid()
        {
            if (robotGuid.Length > 0)
            {
                return;
            }

            string robotFile = PlayerPrefs.GetString("simSelectedRobot") + "\\skeleton.bxdj";

            if (!File.Exists(robotFile))
            {
                CmdCancelSync();
                return;
            }

            Task <RigidNode_Base> loadingTask = new Task <RigidNode_Base>(() => BXDJSkeleton.ReadSkeleton(robotFile));

            loadingTask.ContinueWith(t =>
            {
                if (t.Result == null)
                {
                    CmdCancelSync();
                    return;
                }

                CmdSetRobotGuid(t.Result.GUID.ToString());
            }, TaskScheduler.FromCurrentSynchronizationContext());

            loadingTask.Start();
        }
コード例 #6
0
ファイル: Main.cs プロジェクト: aaroncohen73/synthesis
    bool LoadRobot(string directory)
    {
        robotObject = new GameObject("Robot");
        robotObject.transform.position = robotStartPosition;

        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        rootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        rootNode.ListAllNodes(nodes);

        foreach (RigidNode_Base n in nodes)
        {
            RigidNode node = (RigidNode)n;
            node.CreateTransform(robotObject.transform);

            if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                Destroy(robotObject);
                return(false);
            }

            node.CreateJoint();
        }

        return(true);
    }
コード例 #7
0
    /// <summary>
    /// Save all changes to an open robot
    /// </summary>
    /// <param name="isSaveAs">If this is a "Save As" operation</param>
    /// <returns>If the save operation succeeded</returns>
    public bool SaveRobot(bool isSaveAs)
    {
        if (SkeletonBase == null || Meshes == null)
        {
            return(false);
        }

        string dirPath = lastDirPath;

        if (dirPath == null || isSaveAs)
        {
            dirPath = OpenFolderPath();
        }
        if (dirPath == null)
        {
            return(false);
        }

        if (File.Exists(dirPath + "\\skeleton.bxdj"))
        {
            if (dirPath != lastDirPath && !WarnOverwrite())
            {
                return(false);
            }
        }

        try
        {
            BXDJSkeleton.WriteSkeleton(dirPath + "\\skeleton.bxdj", SkeletonBase);

            for (int i = 0; i < Meshes.Count; i++)
            {
                Meshes[i].WriteToFile(dirPath + "\\node_" + i + ".bxda");
            }

            /*
             * The commented code below is for testing purposes.
             * To determine if the reading/writing process runs
             * without loss of data, compare the text of skeleton.bxdj
             * and skeleton2.bxdj. If they are equal, no data was lost.
             */

            /** /
             * RigidNode_Base testRigidNode = BXDJSkeleton.ReadSkeleton(dirPath + "\\skeleton.bxdj");
             *
             * BXDJSkeleton.WriteSkeleton(dirPath + "\\skeleton2.bxdj", testRigidNode);
             * /**/
        }
        catch (Exception e)
        {
            MessageBox.Show("Couldn't save robot \n" + e.Message);
            return(false);
        }

        MessageBox.Show("Saved!");

        lastDirPath = dirPath;

        return(true);
    }
コード例 #8
0
ファイル: Robot.cs プロジェクト: BraytonK/synthesis
    /// <summary>
    /// Initializes physical robot based off of robot directory.
    /// </summary>
    /// <param name="directory">folder directory of robot</param>
    /// <returns></returns>
    public bool InitializeRobot(string directory, MainState source)
    {
        //Deletes all nodes if any exist
        int childCount = transform.childCount;

        for (int i = 0; i < childCount; ++i)
        {
            Destroy(transform.GetChild(i).gameObject);
        }

        mainState          = source;
        transform.position = robotStartPosition;

        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        //Read .robot instead. Maybe need a RobotSkeleton class
        rootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        rootNode.ListAllNodes(nodes);

        foreach (RigidNode_Base n in nodes)
        {
            RigidNode node = (RigidNode)n;
            node.CreateTransform(transform);

            if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                return(false);
            }

            node.CreateJoint();

            node.MainObject.AddComponent <Tracker>().Trace = true;
        }

        RotateRobot(robotStartOrientation);

        RobotName = new DirectoryInfo(directory).Name;

        isInitialized = true;

        robotCamera = GameObject.Find("RobotCameraList").GetComponent <RobotCamera>();
        //Attached to the main frame and face the front
        robotCamera.AddCamera(transform.GetChild(0).transform);
        //Attached to the first node and face the front
        robotCamera.AddCamera(transform.GetChild(1).transform);
        ////Attached to main frame and face the back
        robotCamera.AddCamera(transform.GetChild(0).transform, new Vector3(0, 0, 0), new Vector3(0, 180, 0));
        return(true);
    }
コード例 #9
0
ファイル: Robot.cs プロジェクト: BraytonK/synthesis
    public bool LoadManipulator(string directory)
    {
        manipulatorObject = new GameObject("Manipulator");

        //Set the manipulator transform to match with the position of node_0 of the robot. THIS ONE ACTUALLY DOES SOMETHING:
        manipulatorObject.transform.position = GameObject.Find("Robot").transform.GetChild(0).transform.position;
        //manipulatorObject.transform.position = robotStartPosition;

        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        //TO-DO: Read .robot instead (from the new exporters if they are implemented). Maybe need a RobotSkeleton class
        manipulatorNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        manipulatorNode.ListAllNodes(nodes);

        //Load node_0 for attaching manipulator to robot
        RigidNode node = (RigidNode)nodes[0];

        node.CreateTransform(manipulatorObject.transform);
        if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
        {
            Debug.Log("Robot not loaded!");
            UnityEngine.Object.Destroy(manipulatorObject);
            return(false);
        }
        node.CreateManipulatorJoint();
        node.MainObject.AddComponent <Tracker>().Trace = true;
        Tracker t = node.MainObject.GetComponent <Tracker>();

        Debug.Log(t);

        //Load other nodes associated with the manipulator
        for (int i = 1; i < nodes.Count; i++)
        {
            RigidNode otherNode = (RigidNode)nodes[i];
            otherNode.CreateTransform(manipulatorObject.transform);
            if (!otherNode.CreateMesh(directory + "\\" + otherNode.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                UnityEngine.Object.Destroy(manipulatorObject);
                return(false);
            }
            otherNode.CreateJoint();
            otherNode.MainObject.AddComponent <Tracker>().Trace = true;
            t = otherNode.MainObject.GetComponent <Tracker>();
            Debug.Log(t);
        }

        RotateRobot(robotStartOrientation);
        return(true);
    }
コード例 #10
0
ファイル: PlayerIdentity.cs プロジェクト: ezhangle/synthesis
        /// <summary>
        /// Checks if the resources held by the other identity need to be transferred to
        /// this instance.
        /// </summary>
        public void CheckDependencies()
        {
            ReceivedFiles.Clear();
            dependencyCount = 0;

            List <int> unresolvedDependencies = new List <int>();

            RobotFolder = PlayerPrefs.GetString("simSelectedRobot");

            foreach (PlayerIdentity otherIdentity in FindObjectsOfType <PlayerIdentity>().Where(p => p.id != id))
            {
                string robotsDirectory = PlayerPrefs.GetString("RobotDirectory");
                otherIdentity.RobotFolder = string.Empty;

                foreach (string dir in Directory.GetDirectories(robotsDirectory, otherIdentity.robotName))
                {
                    RigidNode_Base root = BXDJSkeleton.ReadSkeleton(dir + "\\skeleton.bxdj");

                    if (root.GUID.ToString().Equals(otherIdentity.robotGuid))
                    {
                        otherIdentity.RobotFolder = dir;
                        break;
                    }
                }

                if (otherIdentity.RobotFolder.Length == 0)
                {
                    unresolvedDependencies.Add(otherIdentity.id);
                    otherIdentity.RobotFolder = robotsDirectory + "\\" + otherIdentity.robotName;
                }
            }

            string fieldsDirectory = PlayerPrefs.GetString("FieldDirectory");

            MatchManager.Instance.FieldFolder = string.Empty;

            foreach (string dir in Directory.GetDirectories(fieldsDirectory, MatchManager.Instance.FieldName))
            {
                FieldDefinition definition = BXDFProperties.ReadProperties(dir + "\\definition.bxdf");

                if (definition.GUID.ToString().Equals(MatchManager.Instance.FieldGuid))
                {
                    MatchManager.Instance.FieldFolder = dir;
                    break;
                }
            }

            if (MatchManager.Instance.FieldFolder.Length == 0)
            {
                unresolvedDependencies.Add(-1);
                MatchManager.Instance.FieldFolder = fieldsDirectory + "\\" + MatchManager.Instance.FieldName;
            }

            CmdAddDependencies(unresolvedDependencies.ToArray());
        }
コード例 #11
0
    public static List <BXDAMesh> ExportMeshes(RigidNode_Base baseNode, bool useOCL = false)
    {
        SurfaceExporter surfs = new SurfaceExporter();

        BXDJSkeleton.SetupFileNames(baseNode, true);

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        baseNode.ListAllNodes(nodes);

        SynthesisGUI.Instance.ExporterSetMeshes(nodes.Count);

        List <BXDAMesh> meshes = new List <BXDAMesh>();

        foreach (RigidNode_Base node in nodes)
        {
            SynthesisGUI.Instance.ExporterSetOverallText("Exporting " + node.ModelFileName);

            if (node is RigidNode && node.GetModel() != null && node.ModelFileName != null && node.GetModel() is CustomRigidGroup)
            {
                Console.WriteLine("Exporting " + node.ModelFileName);

                try
                {
                    SynthesisGUI.Instance.ExporterReset();
                    CustomRigidGroup group = (CustomRigidGroup)node.GetModel();
                    surfs.Reset(node.GUID);
                    Console.WriteLine("Exporting meshes...");
                    surfs.ExportAll(group, (long progress, long total) =>
                    {
                        double totalProgress = (((double)progress / (double)total) * 100.0);
                        SynthesisGUI.Instance.ExporterSetSubText(String.Format("Export {1} / {2}", Math.Round(totalProgress, 2), progress, total));
                        SynthesisGUI.Instance.ExporterSetProgress(totalProgress);
                    });
                    Console.WriteLine();
                    BXDAMesh output = surfs.GetOutput();
                    Console.WriteLine("Output: " + output.meshes.Count + " meshes");
                    Console.WriteLine("Computing colliders...");
                    output.colliders.Clear();
                    output.colliders.AddRange(ConvexHullCalculator.GetHull(output));

                    meshes.Add(output);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                    throw new Exception("Error exporting mesh: " + node.GetModelID());
                }
            }

            SynthesisGUI.Instance.ExporterStepOverall();
        }

        return(meshes);
    }
コード例 #12
0
ファイル: MaMRobot.cs プロジェクト: ezhangle/synthesis
        // TODO: Something weird is going on with the spawn, at least with robots with manipulators. Reset is fine.

        /// <summary>
        /// Loads and initializes the physical manipulator object (used in Mix and Match mode)
        /// </summary>
        /// <param name="directory">Folder directory of the manipulator</param>
        /// <param name="robotGameObject">GameObject of the robot the manipulator will be attached to</param>
        public bool InitializeManipulator(string directory)
        {
            ManipulatorObject = new GameObject("Manipulator");
            ManipulatorObject.transform.position = robotStartPosition + manipulatorOffset;

            RigidNode_Base.NODE_FACTORY = delegate(Guid guid) { return(new RigidNode(guid)); };

            List <RigidNode_Base> nodes = new List <RigidNode_Base>();

            //TO-DO: Read .robot instead (from the new exporters if they are implemented). Maybe need a RobotSkeleton class
            manipulatorNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
            manipulatorNode.ListAllNodes(nodes);

            //Load node_0 for attaching manipulator to robot
            RigidNode node = (RigidNode)nodes[0];

            node.CreateTransform(ManipulatorObject.transform);
            if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
            {
                Destroy(ManipulatorObject);
                return(false);
            }

            node.CreateManipulatorJoint(gameObject);
            node.MainObject.AddComponent <Tracker>().Trace = true;

            //Load other nodes associated with the manipulator
            for (int i = 1; i < nodes.Count; i++)
            {
                RigidNode otherNode = (RigidNode)nodes[i];
                otherNode.CreateTransform(ManipulatorObject.transform);

                if (!otherNode.CreateMesh(directory + "\\" + otherNode.ModelFileName))
                {
                    Destroy(ManipulatorObject);
                    return(false);
                }

                otherNode.MainObject.AddComponent <Tracker>().Trace = true;
            }

            RootNode.GenerateWheelInfo();

            for (int i = 1; i < nodes.Count; i++)
            {
                RigidNode otherNode = (RigidNode)nodes[i];
                otherNode.CreateJoint(this);
            }

            RotateRobot(robotStartOrientation);
            RobotHasManipulator = true;

            return(true);
        }
コード例 #13
0
ファイル: WizardForm.cs プロジェクト: j143-zz/synthesis
        public WizardForm()
        {
            InitializeComponent();

            BXDJSkeleton.SetupFileNames(Utilities.GUI.SkeletonBase, true);

            this.Resize += WizardForm_Resize;

            //Start page
            StartPage startPage = new StartPage();

            startPage.ActivateNext   += ActivateNext;
            startPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(startPage, WizardNavigator.WizardNavigatorState.StartEnabled);

            //Step 1: Basic Robot Information
            BasicRobotInfoPage basicRobotInfoPage = new BasicRobotInfoPage();

            basicRobotInfoPage.ActivateNext   += ActivateNext;
            basicRobotInfoPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(basicRobotInfoPage, WizardNavigator.WizardNavigatorState.NextDisabled);

            //Step 2: Define Wheels
            DefineWheelsPage defineWheelsPage = new DefineWheelsPage();

            defineWheelsPage.ActivateNext   += ActivateNext;
            defineWheelsPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(defineWheelsPage, WizardNavigator.WizardNavigatorState.Clean);

            //Step 3: Define other moving parts
            DefineMovingPartsPage defineMovingPartsPage = new DefineMovingPartsPage();

            defineMovingPartsPage.ActivateNext   += ActivateNext;
            defineMovingPartsPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(defineMovingPartsPage, WizardNavigator.WizardNavigatorState.Clean);

            //Step 4: Review and finish
            ReviewAndFinishPage reviewAndFinishPage = new ReviewAndFinishPage();

            reviewAndFinishPage.ActivateNext   += ActivateNext;
            reviewAndFinishPage.DeactivateNext += DeactivateNext;
            WizardPages.Add(reviewAndFinishPage, WizardNavigator.WizardNavigatorState.FinishEnabled);

            WizardPages.BeginWizard();
            WizardPages.FinishClicked += delegate()
            {
                WizardData.Instance.Apply();
                Utilities.GUI.ReloadPanels();
                Close();
            };
        }
コード例 #14
0
    /// <summary>
    /// Open a previously exported robot.
    /// </summary>
    /// <param name="validate">If it is not null, this will validate the open inventor assembly.</param>
    public void OpenExisting()
    {
        if (SkeletonBase != null && !WarnUnsaved())
        {
            return;
        }

        string dirPath = OpenFolderPath();

        if (dirPath == null)
        {
            return;
        }

        try
        {
            List <RigidNode_Base> nodes = new List <RigidNode_Base>();
            SkeletonBase = BXDJSkeleton.ReadSkeleton(dirPath + "\\skeleton.bxdj");

            SkeletonBase.ListAllNodes(nodes);

            Meshes = new List <BXDAMesh>();

            foreach (RigidNode_Base n in nodes)
            {
                BXDAMesh mesh = new BXDAMesh();
                mesh.ReadFromFile(dirPath + "\\" + n.ModelFileName);

                if (!n.GUID.Equals(mesh.GUID))
                {
                    MessageBox.Show(n.ModelFileName + " has been modified.", "Could not load mesh.");
                    return;
                }

                Meshes.Add(mesh);
            }
            for (int i = 0; i < Meshes.Count; i++)
            {
                ((OGL_RigidNode)nodes[i]).loadMeshes(Meshes[i]);
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
        }


        ReloadPanels();
    }
コード例 #15
0
ファイル: Physics.cs プロジェクト: solomondg/synthesis
        /// <summary>
        /// Default Constructor
        /// </summary>
        public Physics()
        {
            DantzigSolver mlcp = new DantzigSolver();

            collisionConf = new SoftBodyRigidBodyCollisionConfiguration();
            dispatcher    = new CollisionDispatcher(new DefaultCollisionConfiguration());
            solver        = new DefaultSoftBodySolver();
            ConstraintSolver cSolver = new MultiBodyConstraintSolver();

            broadphase = new DbvtBroadphase();
            World      = new SoftRigidDynamicsWorld(dispatcher, broadphase, cSolver, collisionConf, solver);

            //Actual scaling is unknown, this gravity is probably not right
            World.Gravity = new Vector3(0, -98.1f, 0);
            World.SetInternalTickCallback(new DynamicsWorld.InternalTickCallback((w, f) => DriveJoints.UpdateAllMotors(Skeleton, cachedArgs)));

            //Roobit
            RigidNode_Base.NODE_FACTORY = (Guid guid) => new BulletRigidNode(guid);
            string RobotPath = @"C:\Program Files (x86)\Autodesk\Synthesis\Synthesis\Robots\";
            string dir       = RobotPath;

            GetFromDirectory(RobotPath, s => { Skeleton = (BulletRigidNode)BXDJSkeleton.ReadSkeleton(s + "skeleton.bxdj"); dir = s; });
            List <RigidNode_Base> nodes = Skeleton.ListAllNodes();

            for (int i = 0; i < nodes.Count; i++)
            {
                BulletRigidNode bNode = (BulletRigidNode)nodes[i];
                bNode.CreateRigidBody(dir + bNode.ModelFileName);
                bNode.CreateJoint();

                if (bNode.joint != null)
                {
                    World.AddConstraint(bNode.joint, true);
                }
                World.AddCollisionObject(bNode.BulletObject);
                collisionShapes.Add(bNode.BulletObject.CollisionShape);
            }

            //Field
            string fieldPath = @"C:\Program Files (x86)\Autodesk\Synthesis\Synthesis\Fields\";

            GetFromDirectory(fieldPath, s => f = BulletFieldDefinition.FromFile(s));

            foreach (RigidBody b in f.Bodies)
            {
                World.AddRigidBody(b);
                collisionShapes.Add(b.CollisionShape);
            }
        }
コード例 #16
0
        /// <summary>
        /// Saves the robot to the directory it was loaded from or the default directory
        /// </summary>
        /// <returns></returns\>
        ///
        public bool ExportRobot()
        {
            try
            {
                WriteLimits(RobotBaseNode);          // write the limits from Inventor to the skeleton

                if (string.IsNullOrEmpty(RobotName)) // If robot has not been named, cancel
                {
                    return(false);
                }

                var robotFolderPath = RobotExporterAddInServer.Instance.AddInSettingsManager.ExportPath + "\\" + RobotName;
                Directory.CreateDirectory(robotFolderPath); // CreateDirectory checks if the folder already exists

                if (!LoadMeshes())                          // Re-export every time because we don't detect changes to the robot CAD
                {
                    return(false);
                }

                BXDJSkeleton.SetupFileNames(RobotBaseNode);
                BXDJSkeletonJson.WriteSkeleton(robotFolderPath + "\\skeleton.json", RobotBaseNode);

                for (var i = 0; i < RobotMeshes.Count; i++)
                {
                    RobotMeshes[i].WriteToFile(robotFolderPath + "\\node_" + i + ".bxda");
                }

                //MessageBox.Show("Your robot was successfully exported to " + robotFolderPath, "Export Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
                if (!RobotExporterAddInServer.Instance.AddInSettingsManager.OpenSynthesis)
                {
                    new ExportSuccessfulForm(robotFolderPath).ShowDialog();
                }

                Settings.Default.ExportCount += 1;     // possibly track the number of exports a user has as another Google Analytics custom field?

                if (Settings.Default.ExportCount == 2) // once user passes 2 exports it will never display again
                {
                    new AnalyticsSurvey().ShowDialog();
                }

                return(true);
            }
            catch (Exception e)
            {
                //TODO: Create a form that displays a simple error message with an option to expand it and view the exception info
                MessageBox.Show("Unable to export robot: " + e.Message, "Export Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }
        }
コード例 #17
0
ファイル: BXDExtensions.cs プロジェクト: xiaodelea/synthesis
        public static RigidNode_Base ReadSkeletonSafe(string path)
        {
            string         jsonPath = path + ".json";
            string         xmlPath  = path + ".bxdj";
            RigidNode_Base node     = null;

            if (File.Exists(jsonPath))
            {
                //Load JSON
                Debug.Log("Loading JSON robot: " + jsonPath);
                node = BXDJSkeletonJson.ReadSkeleton(jsonPath);
            }
            else
            {
                node = BXDJSkeleton.ReadSkeleton(xmlPath);
            }

            return(node);
        }
コード例 #18
0
ファイル: LiteExporterForm.cs プロジェクト: j143-zz/synthesis
    /// <summary>
    /// The lite equivalent of the 'Start Exporter' <see cref="Button"/> in the <see cref="ExporterForm"/>. Used in <see cref="ExporterWorker_DoWork(Object, "/>
    /// </summary>
    /// <seealso cref="ExporterWorker_DoWork"/>
    /// <param name="baseNode"></param>
    /// <returns></returns>
    public List <BXDAMesh> ExportMeshesLite(RigidNode_Base baseNode)
    {
        SurfaceExporter surfs = new SurfaceExporter();

        BXDJSkeleton.SetupFileNames(baseNode, true);

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        baseNode.ListAllNodes(nodes);

        List <BXDAMesh> meshes = new List <BXDAMesh>();

        foreach (RigidNode_Base node in nodes)
        {
            SetProgressText("Exporting " + node.ModelFileName);

            if (node is RigidNode && node.GetModel() != null && node.ModelFileName != null && node.GetModel() is CustomRigidGroup)
            {
                try
                {
                    CustomRigidGroup group = (CustomRigidGroup)node.GetModel();
                    surfs.Reset(node.GUID);
                    surfs.ExportAll(group, (long progress, long total) =>
                    {
                        SetProgressText(String.Format("Export {0} / {1}", progress, total));
                    });
                    BXDAMesh output = surfs.GetOutput();
                    output.colliders.Clear();
                    output.colliders.AddRange(ConvexHullCalculator.GetHull(output));

                    meshes.Add(output);
                }
                catch (Exception e)
                {
                    throw new Exception("Error exporting mesh: " + node.GetModelID(), e);
                }
            }
        }

        return(meshes);
    }
コード例 #19
0
        private void StandaloneViewerForm_Shown(object sender, EventArgs e)
        {
            RigidNode_Base node = BXDJSkeleton.ReadSkeleton(LaunchParams.Path + @"\skeleton.bxdj");

            List <RigidNode_Base> nodes = node.ListAllNodes();

            List <BXDAMesh> meshes = new List <BXDAMesh>();

            foreach (RigidNode_Base n in nodes)
            {
                BXDAMesh mesh = new BXDAMesh();
                mesh.ReadFromFile(LaunchParams.Path + "\\" + n.ModelFileName);

                if (!n.GUID.Equals(mesh.GUID))
                {
                    MessageBox.Show(n.ModelFileName + " has been modified.", "Could not load mesh.");
                }
                meshes.Add(mesh);
            }
            robotViewer1.LoadModel(node, meshes);
            robotViewer1.FixLimits();
            robotViewer1.HighlightAll();
        }
コード例 #20
0
ファイル: RobotBase.cs プロジェクト: chargen/synthesis
        /// <summary>
        /// Initializes physical robot based off of robot directory.
        /// </summary>
        /// <param name="directory">folder directory of robot</param>
        /// <returns></returns>
        public bool InitializeRobot(string directory)
        {
            RobotDirectory = directory;
            RobotName      = new DirectoryInfo(directory).Name;

            //Deletes all nodes if any exist, take the old node transforms out from the robot object
            foreach (Transform child in transform)
            {
                Destroy(child.gameObject);
            }

            robotStartPosition = FieldDataHandler.robotSpawn != new Vector3(99999, 99999, 99999) ? FieldDataHandler.robotSpawn : robotStartPosition;
            transform.position = robotStartPosition; //Sets the position of the object to the set spawn point

            if (!File.Exists(directory + "\\skeleton.bxdj"))
            {
                return(false);
            }

            OnInitializeRobot();

            //Loads the node and skeleton data
            RigidNode_Base.NODE_FACTORY = delegate(Guid guid) { return(new RigidNode(guid)); };

            List <RigidNode_Base> nodes = new List <RigidNode_Base>();

            RootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj") as RigidNode;
            RootNode.ListAllNodes(nodes);

            Debug.Log(RootNode.driveTrainType.ToString());

            emuList = new List <EmuNetworkInfo>();

            foreach (RigidNode_Base Base in RootNode.ListAllNodes())
            {
                try
                {
                    if (Base.GetSkeletalJoint().attachedSensors != null)
                    {
                        foreach (RobotSensor sensor in Base.GetSkeletalJoint().attachedSensors)
                        {
                            if (sensor.type == RobotSensorType.ENCODER)
                            {
                                EmuNetworkInfo emuStruct = new EmuNetworkInfo();
                                emuStruct.encoderTickCount = 0;
                                emuStruct.RobotSensor      = sensor;
                                emuStruct.wheel            = Base;
                                emuStruct.wheel_radius     = 0;

                                emuList.Add(emuStruct);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.Log(e.ToString());
                }
            }

            //Initializes the wheel variables
            float collectiveMass = 0f;

            if (!ConstructRobot(nodes, ref collectiveMass))
            {
                return(false);
            }

            foreach (BRaycastRobot r in GetComponentsInChildren <BRaycastRobot>())
            {
                r.RaycastRobot.OverrideMass  = collectiveMass;
                r.RaycastRobot.RootRigidBody = (RigidBody)((RigidNode)nodes[0]).MainObject.GetComponent <BRigidBody>().GetCollisionObject();
            }

            OnRobotSetup();

            RotateRobot(robotStartOrientation);

            return(true);
        }
コード例 #21
0
ファイル: MaMRobot.cs プロジェクト: ezhangle/synthesis
        /// <summary>
        /// Generates the robot from the list of <see cref="RigidNode_Base"/>s and the
        /// number of wheels, and updates the collective mass.
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="numWheels"></param>
        /// <param name="collectiveMass"></param>
        /// <returns></returns>
        protected override bool ConstructRobot(List <RigidNode_Base> nodes, ref float collectiveMass)
        {
            if (IsMecanum())
            {
                return(base.ConstructRobot(nodes, ref collectiveMass));
            }

            //Load Node_0, the base of the robot
            RigidNode node = (RigidNode)nodes[0];

            node.CreateTransform(transform);

            if (!node.CreateMesh(RobotDirectory + "\\" + node.ModelFileName, true, wheelMass))
            {
                return(false);
            }

            node.CreateJoint(this);

            if (node.PhysicalProperties != null)
            {
                collectiveMass += node.PhysicalProperties.mass;
            }

            if (node.MainObject.GetComponent <BRigidBody>() != null)
            {
                node.MainObject.AddComponent <Tracker>().Trace = true;
            }

            //Get the wheel mesh data from the file they are stored in. They are stored as .bxda files. This may need to update if exporters/file types change.
            BXDAMesh mesh = new BXDAMesh();

            mesh.ReadFromFile(wheelPath + "\\node_0.bxda");

            List <Mesh>       meshList     = new List <Mesh>();
            List <Material[]> materialList = new List <Material[]>();

            RigidNode wheelNode = (RigidNode)BXDJSkeleton.ReadSkeleton(wheelPath + "\\skeleton.bxdj");

            Material[] materials = new Material[0];
            Auxiliary.ReadMeshSet(mesh.meshes, delegate(int id, BXDAMesh.BXDASubMesh sub, Mesh meshu)
            {
                meshList.Add(meshu);

                materials = new Material[meshu.subMeshCount];

                for (int i = 0; i < materials.Length; i++)
                {
                    materials[i] = sub.surfaces[i].AsMaterial(true);
                }

                materialList.Add(materials);
            }, true);

            //Loads the other nodes from the original robot
            for (int i = 1; i < nodes.Count; i++)
            {
                node = (RigidNode)nodes[i];
                node.CreateTransform(transform);

                if (!node.CreateMesh(RobotDirectory + "\\" + node.ModelFileName, true, wheelMass))
                {
                    return(false);
                }

                //If the node is a wheel, destroy the original wheel mesh and replace it with the wheels selected in MaM
                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    int chldCount = node.MainObject.transform.childCount;

                    for (int j = 0; j < chldCount; j++)
                    {
                        Destroy(node.MainObject.transform.GetChild(j).gameObject);
                    }

                    int k = 0;

                    Vector3?offset = null;
                    foreach (Mesh meshObject in meshList)
                    {
                        GameObject meshObj = new GameObject(node.MainObject.name + "_mesh");
                        meshObj.transform.parent = node.MainObject.transform;
                        meshObj.AddComponent <MeshFilter>().mesh = meshObject;

                        if (!offset.HasValue)
                        {
                            offset = meshObject.bounds.center;
                        }

                        meshObj.transform.localPosition = -offset.Value;

                        //Take out this line if you want some snazzy pink wheels
                        meshObj.AddComponent <MeshRenderer>().materials = materialList[k];

                        k++;
                    }
                    node.MainObject.GetComponentInChildren <MeshRenderer>().materials = materials;
                }
            }

            RootNode.GenerateWheelInfo();

            //Create the joints that interact with physics
            for (int i = 1; i < nodes.Count; i++)
            {
                node = (RigidNode)nodes[i];
                node.CreateJoint(this, wheelFriction, wheelLateralFriction);

                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    node.MainObject.GetComponent <BRaycastWheel>().Radius = wheelRadius;
                }

                if (node.PhysicalProperties != null)
                {
                    collectiveMass += node.PhysicalProperties.mass;
                }

                if (node.MainObject.GetComponent <BRigidBody>() != null)
                {
                    node.MainObject.AddComponent <Tracker>().Trace = true;
                }
            }

            return(true);
        }
コード例 #22
0
ファイル: Robot.cs プロジェクト: j143-zz/synthesis
    /// <summary>
    /// Initializes physical robot based off of robot directory.
    /// </summary>
    /// <param name="directory">folder directory of robot</param>
    /// <returns></returns>
    public bool InitializeRobot(string directory, MainState source)
    {
        RobotIsMecanum = false;

        if (RobotIsMixAndMatch)
        {
            wheelPath            = RobotTypeManager.WheelPath;
            wheelFriction        = RobotTypeManager.WheelFriction;
            wheelLateralFriction = RobotTypeManager.WheelLateralFriction;
            wheelRadius          = RobotTypeManager.WheelRadius;
            wheelMass            = RobotTypeManager.WheelMass;

            RobotIsMecanum = RobotTypeManager.IsMecanum;
        }

        #region Robot Initialization
        RobotDirectory = directory;

        //Deletes all nodes if any exist, take the old node transforms out from the robot object
        int childCount = transform.childCount;
        for (int i = childCount - 1; i >= 0; i--)
        {
            Transform child = transform.GetChild(i);

            //If this isn't done, the game object is destroyed but the parent-child transform relationship remains!
            child.parent = null;
            Destroy(child.gameObject);
        }

        //Detach and destroy all sensors on the original robot
        SensorManager sensorManager = GameObject.Find("SensorManager").GetComponent <SensorManager>();
        sensorManager.ResetSensorLists();



        //Removes Driver Practice component if it exists
        if (dpmRobot != null)
        {
            Destroy(dpmRobot);
        }

        mainState = source;                      //stores the main state object

        transform.position = robotStartPosition; //Sets the position of the object to the set spawn point

        if (!File.Exists(directory + "\\skeleton.bxdj"))
        {
            return(false);
        }

        //Loads the node and skeleton data
        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };
        List <RigidNode_Base> nodes = new List <RigidNode_Base>();
        rootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        rootNode.ListAllNodes(nodes);

        //Initializes the wheel variables
        int   numWheels      = nodes.Count(x => x.HasDriverMeta <WheelDriverMeta>() && x.GetDriverMeta <WheelDriverMeta>().type != WheelType.NOT_A_WHEEL);
        float collectiveMass = 0f;


        //Initializes the nodes and creates joints for the robot
        if (RobotIsMixAndMatch && !RobotIsMecanum) //If the user is in MaM and the robot they select is not mecanum, create the nodes and replace the wheel meshes to match those selected
        {
            //Load Node_0, the base of the robot
            RigidNode node = (RigidNode)nodes[0];
            node.CreateTransform(transform);

            if (!node.CreateMesh(directory + "\\" + node.ModelFileName, true, wheelMass))
            {
                Debug.Log("Robot not loaded!");
                return(false);
            }

            node.CreateJoint(numWheels, RobotIsMixAndMatch);

            if (node.PhysicalProperties != null)
            {
                collectiveMass += node.PhysicalProperties.mass;
            }

            if (node.MainObject.GetComponent <BRigidBody>() != null)
            {
                node.MainObject.AddComponent <Tracker>().Trace = true;
            }

            //Get the wheel mesh data from the file they are stored in. They are stored as .bxda files. This may need to update if exporters/file types change.
            BXDAMesh mesh = new BXDAMesh();
            mesh.ReadFromFile(wheelPath + "\\node_0.bxda");

            List <Mesh>       meshList     = new List <Mesh>();
            List <Material[]> materialList = new List <Material[]>();

            RigidNode wheelNode = (RigidNode)BXDJSkeleton.ReadSkeleton(wheelPath + "\\skeleton.bxdj");

            Material[] materials = new Material[0];
            AuxFunctions.ReadMeshSet(mesh.meshes, delegate(int id, BXDAMesh.BXDASubMesh sub, Mesh meshu)
            {
                meshList.Add(meshu);

                materials = new Material[meshu.subMeshCount];
                for (int i = 0; i < materials.Length; i++)
                {
                    materials[i] = sub.surfaces[i].AsMaterial(true);
                }

                materialList.Add(materials);
            }, true);


            //Loads the other nodes from the original robot
            for (int i = 1; i < nodes.Count; i++)
            {
                node = (RigidNode)nodes[i];
                node.CreateTransform(transform);

                if (!node.CreateMesh(directory + "\\" + node.ModelFileName, true, wheelMass))
                {
                    Debug.Log("Robot not loaded!");
                    return(false);
                }

                //If the node is a wheel, destroy the original wheel mesh and replace it with the wheels selected in MaM
                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    int chldCount = node.MainObject.transform.childCount;
                    for (int j = 0; j < chldCount; j++)
                    {
                        Destroy(node.MainObject.transform.GetChild(j).gameObject);
                    }

                    int k = 0;

                    Vector3?offset = null;
                    foreach (Mesh meshObject in meshList)
                    {
                        GameObject meshObj = new GameObject(node.MainObject.name + "_mesh");
                        meshObj.transform.parent = node.MainObject.transform;
                        meshObj.AddComponent <MeshFilter>().mesh = meshObject;
                        if (!offset.HasValue)
                        {
                            offset = meshObject.bounds.center;
                        }
                        meshObj.transform.localPosition = -offset.Value;

                        //Take out this line if you want some snazzy pink wheels
                        meshObj.AddComponent <MeshRenderer>().materials = materialList[k];

                        k++;
                    }
                    node.MainObject.GetComponentInChildren <MeshRenderer>().materials = materials;
                }

                //Create the joints that interact with physics
                node.CreateJoint(numWheels, RobotIsMixAndMatch, wheelFriction, wheelLateralFriction);

                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    node.MainObject.GetComponent <BRaycastWheel>().Radius = wheelRadius;
                }

                if (node.PhysicalProperties != null)
                {
                    collectiveMass += node.PhysicalProperties.mass;
                }

                if (node.MainObject.GetComponent <BRigidBody>() != null)
                {
                    node.MainObject.AddComponent <Tracker>().Trace = true;
                }
            }
        }
        else //Initialize the robot as normal
        {
            //Initializes the nodes
            foreach (RigidNode_Base n in nodes)
            {
                RigidNode node = (RigidNode)n;
                node.CreateTransform(transform);

                if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
                {
                    Debug.Log("Robot not loaded!");
                    return(false);
                }

                node.CreateJoint(numWheels, RobotIsMixAndMatch);

                if (node.PhysicalProperties != null)
                {
                    collectiveMass += node.PhysicalProperties.mass;
                }

                if (node.MainObject.GetComponent <BRigidBody>() != null)
                {
                    node.MainObject.AddComponent <Tracker>().Trace = true;
                }
            }
        }

        #endregion

        //Get the offset from the first node to the robot for new robot start position calculation
        //This line is CRITICAL to new reset position accuracy! DON'T DELETE IT!
        nodeToRobotOffset = gameObject.transform.GetChild(0).localPosition - robotStartPosition;

        foreach (BRaycastRobot r in GetComponentsInChildren <BRaycastRobot>())
        {
            r.RaycastRobot.OverrideMass  = collectiveMass;
            r.RaycastRobot.RootRigidBody = (RigidBody)((RigidNode)nodes[0]).MainObject.GetComponent <BRigidBody>().GetCollisionObject();
        }

        RotateRobot(robotStartOrientation);

        RobotName = new DirectoryInfo(directory).Name;

        isInitialized = true;

        //Initializes Driver Practice component
        dpmRobot = gameObject.AddComponent <DriverPracticeRobot>();
        dpmRobot.Initialize(directory);

        //Initializing robot cameras
        bool hasRobotCamera = false;
        //If you are getting an error referencing this line, it is likely that the Game Object "RobotCameraList" in Scene.unity does not have the RobotCameraManager script attached to it.
        robotCameraManager = GameObject.Find("RobotCameraList").GetComponent <RobotCameraManager>();

        //Loop through robotCameraList and check if any existing camera should attach to this robot
        foreach (GameObject robotCamera in robotCameraManager.GetRobotCameraList())
        {
            if (robotCamera.GetComponent <RobotCamera>().robot.Equals(this))
            {
                //Recover the robot camera configurations
                robotCamera.GetComponent <RobotCamera>().RecoverConfiguration();
                hasRobotCamera = true;
            }
        }
        //Add new cameras to the robot if there is none robot camera belong to the current robot (which means it is a new robot)
        if (!hasRobotCamera)
        {
            //Attached to the main frame and face the front
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform, new Vector3(0, 0.5f, 0), new Vector3(0, 0, 0));
            ////Attached to main frame and face the back
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform, new Vector3(0, 0.5f, 0), new Vector3(0, 180, 0));
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform);
        }

        //Reads the offset position for the manipulator
        if (RobotIsMixAndMatch)
        {
            offset = Vector3.zero;
            try
            {
                using (TextReader reader = File.OpenText(directory + "\\position.txt"))
                {
                    offset.x = float.Parse(reader.ReadLine());
                    offset.y = float.Parse(reader.ReadLine());
                    offset.z = float.Parse(reader.ReadLine());
                }
            } catch
            {
                offset = Vector3.zero;
            }
        }

        return(true);
    }
コード例 #23
0
    /// <summary>
    /// Open a previously exported robot.
    /// </summary>
    /// <param name="validate">If it is not null, this will validate the open inventor assembly.</param>
    public bool OpenExisting(ValidationAction validate, bool warnUnsaved = false)
    {
        if (SkeletonBase != null && warnUnsaved && !WarnUnsaved())
        {
            return(false);
        }

        string dirPath = OpenFolderPath();

        if (dirPath == null)
        {
            return(false);
        }

        try
        {
            List <RigidNode_Base> nodes = new List <RigidNode_Base>();
            SkeletonBase = BXDJSkeleton.ReadSkeleton(dirPath + "\\skeleton.bxdj");

            if (validate != null)
            {
                if (!validate(SkeletonBase, out string message))
                {
                    while (true)
                    {
                        DialogResult result = MessageBox.Show(message, "Assembly Validation", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        if (result == DialogResult.Retry)
                        {
                            continue;
                        }
                        if (result == DialogResult.Abort)
                        {
                            return(false);
                        }
                        break;
                    }
                }
                #region DEBUG
#if DEBUG
                else
                {
                    MessageBox.Show(message);
                }
#endif
                #endregion
            }

            SkeletonBase.ListAllNodes(nodes);

            Meshes = new List <BXDAMesh>();

            foreach (RigidNode_Base n in nodes)
            {
                BXDAMesh mesh = new BXDAMesh();
                mesh.ReadFromFile(dirPath + "\\" + n.ModelFileName);

                if (!n.GUID.Equals(mesh.GUID))
                {
                    MessageBox.Show(n.ModelFileName + " has been modified.", "Could not load mesh.");
                    return(false);
                }

                Meshes.Add(mesh);
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.ToString());
        }

        RMeta.UseSettingsDir  = false;
        RMeta.ActiveDir       = dirPath;
        RMeta.ActiveRobotName = dirPath.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).Last();

        ReloadPanels();
        return(true);
    }
コード例 #24
0
ファイル: Robot.cs プロジェクト: j143-zz/synthesis
    /// <summary>
    /// Loads and initializes the physical manipulator object (used in Mix and Match mode)
    /// </summary>
    /// <param name="directory">Folder directory of the manipulator</param>
    /// <param name="robotGameObject">GameObject of the robot the manipulator will be attached to</param>
    public bool InitializeManipulator(string directory, GameObject robotGameObject)
    {
        if (robotGameObject == null)
        {
            robotGameObject = GameObject.Find("Robot");
        }
        ManipulatorObject = new GameObject("Manipulator");

        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        //TO-DO: Read .robot instead (from the new exporters if they are implemented). Maybe need a RobotSkeleton class
        manipulatorNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        manipulatorNode.ListAllNodes(nodes);

        int   numWheels      = nodes.Count(x => x.HasDriverMeta <WheelDriverMeta>() && x.GetDriverMeta <WheelDriverMeta>().type != WheelType.NOT_A_WHEEL);
        float collectiveMass = 0f;

        //Load node_0 for attaching manipulator to robot
        RigidNode node = (RigidNode)nodes[0];

        node.CreateTransform(ManipulatorObject.transform);
        if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
        {
            Debug.Log("Robot not loaded!");
            UnityEngine.Object.Destroy(ManipulatorObject);
            return(false);
        }
        GameObject robot = robotGameObject;

        //Set the manipulator transform to match with the position of node_0 of the robot. THIS ONE ACTUALLY DOES SOMETHING: LIKE ACTUALLY



        Vector3 manipulatorTransform = robotStartPosition + offset;

        Debug.Log("Node Com Offset" + node.ComOffset);
        ManipulatorObject.transform.position = manipulatorTransform;

        node.CreateManipulatorJoint(robot);
        node.MainObject.AddComponent <Tracker>().Trace = true;
        Tracker t = node.MainObject.GetComponent <Tracker>();

        Debug.Log(t);

        //Load other nodes associated with the manipulator
        for (int i = 1; i < nodes.Count; i++)
        {
            RigidNode otherNode = (RigidNode)nodes[i];
            otherNode.CreateTransform(ManipulatorObject.transform);
            if (!otherNode.CreateMesh(directory + "\\" + otherNode.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                UnityEngine.Object.Destroy(ManipulatorObject);
                return(false);
            }
            otherNode.CreateJoint(numWheels, RobotIsMixAndMatch);
            otherNode.MainObject.AddComponent <Tracker>().Trace = true;
            t = otherNode.MainObject.GetComponent <Tracker>();
            Debug.Log(t);
        }

        foreach (BRaycastRobot r in ManipulatorObject.GetComponentsInChildren <BRaycastRobot>())
        {
            r.RaycastRobot.OverrideMass = collectiveMass;
        }

        RotateRobot(robotStartOrientation);

        this.RobotHasManipulator = true;
        return(true);
    }
コード例 #25
0
ファイル: Init.cs プロジェクト: solomondg/synthesis
    /// <summary>
    /// Loads a robot from file into the simulator.
    /// </summary>
    private void TryLoadRobot()
    {
        //resets rotation for new robot
        rotation = Quaternion.identity;
        if (activeRobot != null)
        {
            skeleton = null;
            UnityEngine.Object.Destroy(activeRobot);
        }
        if (filePath != null && skeleton == null)
        {
            //Debug.Log (filePath);
            List <Collider> meshColliders = new List <Collider>();
            activeRobot = new GameObject("Robot");
            activeRobot.transform.parent = transform;

            List <RigidNode_Base> names = new List <RigidNode_Base>();
            RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
            {
                return(new UnityRigidNode(guid));
            };

            skeleton = BXDJSkeleton.ReadSkeleton(filePath + "skeleton.bxdj");
            //Debug.Log(filePath + "skeleton.bxdj");
            skeleton.ListAllNodes(names);
            foreach (RigidNode_Base node in names)
            {
                UnityRigidNode uNode = (UnityRigidNode)node;

                uNode.CreateTransform(activeRobot.transform);

                if (!uNode.CreateMesh(filePath + uNode.ModelFileName))
                {
                    UserMessageManager.Dispatch(node.ModelFileName + " has been modified and cannot be loaded.", 6f);
                    skeleton = null;
                    UnityEngine.Object.Destroy(activeRobot);
                    return;
                }

                uNode.CreateJoint();

                Debug.Log("Joint");

                meshColliders.AddRange(uNode.unityObject.GetComponentsInChildren <Collider>());
            }

            {                                                                                // Add some mass to the base object
                UnityRigidNode uNode = (UnityRigidNode)skeleton;
                uNode.unityObject.transform.rigidbody.mass += 20f * PHYSICS_MASS_MULTIPLIER; // Battery'
            }

            //finds main node of robot to use its rigidbody
            mainNode = GameObject.Find("node_0.bxda");

            //Debug.Log ("HELLO AMIREKA: " + mainNode);
            auxFunctions.IgnoreCollisionDetection(meshColliders);
            resetRobot();
        }
        else
        {
            Debug.Log("unityWheelData is null...");
        }
        HideGuiSidebar();
    }
コード例 #26
0
        /// <summary>
        /// Detects all the wheel nodes in a robot. Needs improvement
        /// </summary>
        /// <param name="baseNode"></param>
        /// <param name="driveTrain"></param>
        /// <param name="wheelCount"></param>
        /// <returns></returns>
        public static List <RigidNode_Base> DetectWheels(RigidNode_Base baseNode, WizardData.WizardDriveTrain driveTrain, int wheelCount)
        {
            List <RigidNode_Base> jointParentFilter = new List <RigidNode_Base>();

            foreach (RigidNode_Base node in baseNode.ListAllNodes())
            {
                //For the first filter, we take out any nodes that do not have parents and rotational joints.
                if (node.GetParent() != null && node.GetSkeletalJoint() != null && node.GetSkeletalJoint().GetJointType() == SkeletalJointType.ROTATIONAL)
                {
                    jointParentFilter.Add(node);
                }
            }

            //Find node with the lowest y value
            RigidNode_Base lowestNode = null; double lowestY = double.MaxValue;

            foreach (RigidNode_Base node in jointParentFilter)
            {
                if (lowestNode == null)
                {
                    lowestNode = node;
                    lowestY    = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.y;
                }
                else
                {
                    if (node.GetSkeletalJoint().GetAngularDOF().First().basePoint.y < lowestY)
                    {
                        lowestNode = node;
                        lowestY    = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.y;
                    }
                }
            }

            //Find all nodes with y values within 0.1
            List <RigidNode_Base> lowestNodesFilter = new List <RigidNode_Base>();

            foreach (RigidNode_Base node in jointParentFilter)
            {
                if (node == lowestNode)
                {
                    lowestNodesFilter.Add(node);
                }
                else if (lowestY - node.GetSkeletalJoint().GetAngularDOF().First().basePoint.y <= 0.1d && lowestY - node.GetSkeletalJoint().GetAngularDOF().First().basePoint.y >= -0.1d)
                {
                    lowestNodesFilter.Add(node);
                }
            }
            //Hopefully this will be enough filtering :point_right:
            if (lowestNodesFilter.Count == wheelCount)
            {
                BXDJSkeleton.SetupFileNames(baseNode);
                StandardAddInServer.Instance.JointEditorPane_SelectedJoint(lowestNodesFilter);
                return(lowestNodesFilter);
            }

            //Find the nodes with the highest and lowest x values
            RigidNode_Base leftMostNode = null; double highestX = double.MinValue;
            RigidNode_Base rightMostNode = null; double lowestX = double.MaxValue;

            foreach (RigidNode_Base node in lowestNodesFilter)
            {
                if (highestX == double.MinValue)
                {
                    leftMostNode = node;
                    highestX     = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x;
                }
                else if (node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x > highestX)
                {
                    leftMostNode = node;
                    highestX     = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x;
                }

                if (lowestX == double.MaxValue)
                {
                    rightMostNode = node;
                    lowestX       = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x;
                }
                else if (node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x < lowestX)
                {
                    leftMostNode = node;
                    lowestX      = node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x;
                }
            }


            //Find all the nodes with x values within 0.1 of both.
            List <RigidNode_Base> rightWheels = new List <RigidNode_Base> {
                rightMostNode
            };
            List <RigidNode_Base> leftWheels = new List <RigidNode_Base> {
                leftMostNode
            };

            foreach (RigidNode_Base node in lowestNodesFilter)
            {
                if (node == leftMostNode || node == rightMostNode)
                {
                    continue;
                }
                if (node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x - lowestX <= 0.1d && node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x - lowestX >= -0.1d)
                {
                    rightWheels.Add(node);
                }
                else if (node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x - highestX <= 0.1d && node.GetSkeletalJoint().GetAngularDOF().First().basePoint.x - highestX >= -0.1d)
                {
                    leftWheels.Add(node);
                }
            }

            string nodes = "Nodes detected: ";
            List <RigidNode_Base> wheels = new List <RigidNode_Base>();

            wheels.AddRange(rightWheels);
            wheels.AddRange(leftWheels);

            BXDJSkeleton.SetupFileNames(baseNode);
            foreach (var node in wheels)
            {
                nodes += node.ModelFileName + ", ";
            }
            #region DEBUG
#if DEBUG
            MessageBox.Show(nodes);
#endif
            #endregion

            return(wheels);
        }
コード例 #27
0
    /// <summary>
    /// Initializes physical robot based off of robot directory.
    /// </summary>
    /// <param name="directory">folder directory of robot</param>
    /// <returns></returns>
    public bool InitializeRobot(string directory, MainState source)
    {
        #region Robot Initialization
        RobotDirectory = directory;

        //Deletes all nodes if any exist, take the old node transforms out from the robot object
        int childCount = transform.childCount;
        for (int i = childCount - 1; i >= 0; i--)
        {
            Transform child = transform.GetChild(i);

            //If this isn't done, the game object is destroyed but the parent-child transform relationship remains!
            child.parent = null;
            Destroy(child.gameObject);
        }

        //Detach and destroy all sensors on the original robot
        SensorManager sensorManager = GameObject.Find("SensorManager").GetComponent <SensorManager>();
        sensorManager.ResetSensorLists();

        //Removes Driver Practice component if it exists
        if (dpmRobot != null)
        {
            Destroy(dpmRobot);
        }

        mainState = source;                      //stores the main state object

        transform.position = robotStartPosition; //Sets the position of the object to the set spawn point

        if (!File.Exists(directory + "\\skeleton.bxdj"))
        {
            return(false);
        }

        //Loads the node and skeleton data
        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };
        List <RigidNode_Base> nodes = new List <RigidNode_Base>();
        rootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        rootNode.ListAllNodes(nodes);

        //Initializes the wheel variables
        int   numWheels      = nodes.Count(x => x.HasDriverMeta <WheelDriverMeta>() && x.GetDriverMeta <WheelDriverMeta>().type != WheelType.NOT_A_WHEEL);
        float collectiveMass = 0f;

        int isMixAndMatch = PlayerPrefs.GetInt("mixAndMatch");
        if (isMixAndMatch == 1 && !MixAndMatchMode.isMecanum)
        {
            //Load Node_0
            RigidNode node = (RigidNode)nodes[0];
            node.CreateTransform(transform);

            if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                return(false);
            }

            node.CreateJoint(numWheels);

            if (node.PhysicalProperties != null)
            {
                collectiveMass += node.PhysicalProperties.mass;
            }

            if (node.MainObject.GetComponent <BRigidBody>() != null)
            {
                node.MainObject.AddComponent <Tracker>().Trace = true;
            }

            //Load the other nodes (wheels)
            string   wheelDirectory = PlayerPrefs.GetString("simSelectedWheel");
            BXDAMesh mesh           = new BXDAMesh();
            mesh.ReadFromFile(wheelDirectory + "\\node_0.bxda");

            List <Mesh>       meshList     = new List <Mesh>();
            List <Material[]> materialList = new List <Material[]>();

            RigidNode wheelNode = (RigidNode)BXDJSkeleton.ReadSkeleton(wheelDirectory + "\\skeleton.bxdj");

            Material[] materials = new Material[0];
            AuxFunctions.ReadMeshSet(mesh.meshes, delegate(int id, BXDAMesh.BXDASubMesh sub, Mesh meshu)
            {
                meshList.Add(meshu);

                materials = new Material[meshu.subMeshCount];
                for (int i = 0; i < materials.Length; i++)
                {
                    materials[i] = sub.surfaces[i].AsMaterial(true);
                }

                materialList.Add(materials);
                //meshObject.GetComponent<MeshRenderer>().materials = materials;
            }, true);

            for (int i = 1; i < nodes.Count; i++)
            {
                node = (RigidNode)nodes[i];
                node.CreateTransform(transform);

                if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
                {
                    Debug.Log("Robot not loaded!");
                    return(false);
                }

                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    int chldCount = node.MainObject.transform.childCount;
                    for (int j = 0; j < chldCount; j++)
                    {
                        Destroy(node.MainObject.transform.GetChild(j).gameObject);
                    }

                    int k = 0;
                    foreach (Mesh meshObject in meshList)
                    {
                        Debug.Log("Mesh Object" + meshObject);
                        GameObject meshObj = new GameObject(node.MainObject.name + "_mesh");
                        meshObj.transform.parent = node.MainObject.transform;
                        meshObj.AddComponent <MeshFilter>().mesh = meshObject;
                        meshObj.transform.localPosition          = -meshObject.bounds.center;

                        //Take out this line if you want some snazzy pink wheels
                        meshObj.AddComponent <MeshRenderer>().materials = materialList[k];
                        k++;
                    }
                    node.MainObject.GetComponentInChildren <MeshRenderer>().materials = materials;
                }

                //node.MainObject.transform.GetChild(0).localPosition = -node.MainObject.GetComponentInChildren<MeshFilter>().mesh.bounds.center;// -node.MainObject.transform.localPosition;
                //Bounds b = node.MainObject.GetComponentInChildren<MeshFilter>().mesh.bounds;
                // Debug.Log(b.center);
                //b.center = node.MainObject.transform.position;
                //node.MainObject.GetComponentInChildren<MeshFilter>().mesh.bounds = b;

                node.CreateJoint(numWheels);

                if (node.HasDriverMeta <WheelDriverMeta>())
                {
                    float radius = PlayerPrefs.GetFloat("wheelRadius");
                    node.MainObject.GetComponent <BRaycastWheel>().Radius = radius;
                }

                if (node.PhysicalProperties != null)
                {
                    collectiveMass += node.PhysicalProperties.mass;
                }

                if (node.MainObject.GetComponent <BRigidBody>() != null)
                {
                    node.MainObject.AddComponent <Tracker>().Trace = true;
                }
            }
        }
        else
        {
            //Initializes the nodes
            foreach (RigidNode_Base n in nodes)
            {
                RigidNode node = (RigidNode)n;
                node.CreateTransform(transform);

                if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
                {
                    Debug.Log("Robot not loaded!");
                    return(false);
                }

                node.CreateJoint(numWheels);

                if (node.PhysicalProperties != null)
                {
                    collectiveMass += node.PhysicalProperties.mass;
                }

                if (node.MainObject.GetComponent <BRigidBody>() != null)
                {
                    node.MainObject.AddComponent <Tracker>().Trace = true;
                }
            }
        }

        #endregion


        //Get the offset from the first node to the robot for new robot start position calculation
        //This line is CRITICAL to new reset position accuracy! DON'T DELETE IT!
        nodeToRobotOffset = gameObject.transform.GetChild(0).localPosition - robotStartPosition;

        foreach (BRaycastRobot r in GetComponentsInChildren <BRaycastRobot>())
        {
            r.RaycastRobot.OverrideMass  = collectiveMass;
            r.RaycastRobot.RootRigidBody = (RigidBody)((RigidNode)nodes[0]).MainObject.GetComponent <BRigidBody>().GetCollisionObject();
        }

        RotateRobot(robotStartOrientation);

        RobotName = new DirectoryInfo(directory).Name;

        isInitialized = true;

        //Initializes Driver Practice component
        dpmRobot = gameObject.AddComponent <DriverPracticeRobot>();
        dpmRobot.Initialize(directory);

        //Initializing robot cameras
        bool hasRobotCamera = false;
        //If you are getting an error referencing this line, it is likely that the Game Object "RobotCameraList" in Scene.unity does not have the RobotCameraManager script attached to it.
        robotCameraManager = GameObject.Find("RobotCameraList").GetComponent <RobotCameraManager>();

        //Loop through robotCameraList and check if any existing camera should attach to this robot
        foreach (GameObject robotCamera in robotCameraManager.GetRobotCameraList())
        {
            if (robotCamera.GetComponent <RobotCamera>().robot.Equals(this))
            {
                //Recover the robot camera configurations
                robotCamera.GetComponent <RobotCamera>().RecoverConfiguration();
                hasRobotCamera = true;
            }
        }
        //Add new cameras to the robot if there is none robot camera belong to the current robot (which means it is a new robot)
        if (!hasRobotCamera)
        {
            //Attached to the main frame and face the front
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform);
            //Attached to the first node and face the front
            if (transform.childCount > 1)
            {
                robotCameraManager.AddCamera(this, transform.GetChild(1).transform);
            }
            ////Attached to main frame and face the back
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform, new Vector3(0, 0, 0), new Vector3(0, 180, 0));
        }

        return(true);
    }
コード例 #28
0
    /// <summary>
    /// Initializes physical robot based off of robot directory.
    /// </summary>
    /// <param name="directory">folder directory of robot</param>
    /// <returns></returns>
    public bool InitializeRobot(string directory, MainState source)
    {
        //Deletes all nodes if any exist, take the old node transforms out from the robot object
        int childCount = transform.childCount;

        for (int i = childCount - 1; i >= 0; i--)
        {
            Transform child = transform.GetChild(i);

            //If not do this the game object is destroyed but the parent-child transform relationship remains!
            child.parent = null;
            Destroy(child.gameObject);
        }
        SensorManager sensorManager = GameObject.Find("SensorManager").GetComponent <SensorManager>();

        sensorManager.ResetSensorLists();

        mainState          = source;
        transform.position = robotStartPosition;

        RigidNode_Base.NODE_FACTORY = delegate(Guid guid)
        {
            return(new RigidNode(guid));
        };

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        //Read .robot instead. Maybe need a RobotSkeleton class
        rootNode = BXDJSkeleton.ReadSkeleton(directory + "\\skeleton.bxdj");
        rootNode.ListAllNodes(nodes);

        int   numWheels      = nodes.Count(x => x.HasDriverMeta <WheelDriverMeta>() && x.GetDriverMeta <WheelDriverMeta>().type != WheelType.NOT_A_WHEEL);
        float collectiveMass = 0f;

        foreach (RigidNode_Base n in nodes)
        {
            RigidNode node = (RigidNode)n;
            node.CreateTransform(transform);

            if (!node.CreateMesh(directory + "\\" + node.ModelFileName))
            {
                Debug.Log("Robot not loaded!");
                return(false);
            }

            node.CreateJoint(numWheels);

            if (node.PhysicalProperties != null)
            {
                collectiveMass += node.PhysicalProperties.mass;
            }

            if (node.MainObject.GetComponent <BRigidBody>() != null)
            {
                node.MainObject.AddComponent <Tracker>().Trace = true;
            }
        }

        foreach (BRaycastRobot r in GetComponentsInChildren <BRaycastRobot>())
        {
            r.RaycastRobot.EffectiveMass = collectiveMass;
        }

        RotateRobot(robotStartOrientation);

        RobotName = new DirectoryInfo(directory).Name;

        isInitialized = true;

        bool hasRobotCamera = false;

        robotCameraManager = GameObject.Find("RobotCameraList").GetComponent <RobotCameraManager>();

        foreach (GameObject robotCamera in robotCameraManager.GetRobotCameraList())
        {
            if (robotCamera.GetComponent <RobotCamera>().robot.Equals(this))
            {
                robotCamera.GetComponent <RobotCamera>().RecoverConfiguration();
                hasRobotCamera = true;
                Debug.Log(hasRobotCamera);
            }
        }
        if (!hasRobotCamera)
        {
            //Attached to the main frame and face the front
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform);
            //Attached to the first node and face the front
            if (transform.childCount > 1)
            {
                robotCameraManager.AddCamera(this, transform.GetChild(1).transform);
            }
            ////Attached to main frame and face the back
            robotCameraManager.AddCamera(this, transform.GetChild(0).transform, new Vector3(0, 0, 0), new Vector3(0, 180, 0));
        }

        //sensorManager.AddBeamBreaker(transform.GetChild(0).gameObject, new Vector3(0, 0, 1), new Vector3(0, 90, 0), 1);
        //sensorManager.AddUltrasonicSensor(transform.GetChild(0).gameObject, new Vector3(0, 0, 0), new Vector3(0, 0, 0));
        //sensorManager.AddGyro(transform.GetChild(0).gameObject, new Vector3(0, 0, 0), new Vector3(0, 0, 0));
        return(true);
    }
コード例 #29
0
    /// <summary>
    /// The lite equivalent of the 'Start Exporter' <see cref="Button"/> in the <see cref="ExporterForm"/>. Used in <see cref="ExporterWorker_DoWork(Object, "/>
    /// </summary>
    /// <seealso cref="ExporterWorker_DoWork"/>
    /// <param name="baseNode"></param>
    /// <returns></returns>
    public List <BXDAMesh> ExportMeshesLite(RigidNode_Base baseNode, float totalMassKg)
    {
        SurfaceExporter surfs = new SurfaceExporter();

        BXDJSkeleton.SetupFileNames(baseNode);

        List <RigidNode_Base> nodes = new List <RigidNode_Base>();

        baseNode.ListAllNodes(nodes);

        List <BXDAMesh> meshes = new List <BXDAMesh>();

        SetProgress(0, "Exporting Model");

        for (int i = 0; i < nodes.Count; i++)
        {
            RigidNode_Base node = nodes[i];

            if (node is RigidNode && node.GetModel() != null && node.ModelFileName != null && node.GetModel() is CustomRigidGroup)
            {
                try
                {
                    CustomRigidGroup group = (CustomRigidGroup)node.GetModel();

                    BXDAMesh output = surfs.ExportAll(group, node.GUID, (long progress, long total) =>
                    {
                        SetProgress(((double)progress / total) / nodes.Count + (double)i / nodes.Count);
                    });

                    output.colliders.Clear();
                    output.colliders.AddRange(ConvexHullCalculator.GetHull(output));

                    meshes.Add(output);
                }
                catch (Exception e)
                {
                    throw new Exception("Error exporting mesh: " + node.GetModelID(), e);
                }
            }
        }

        // Apply custom mass to mesh
        if (totalMassKg > 0) // Negative value indicates that default mass should be left alone (TODO: Make default mass more accurate)
        {
            float totalDefaultMass = 0;
            foreach (BXDAMesh mesh in meshes)
            {
                totalDefaultMass += mesh.physics.mass;
            }
            for (int i = 0; i < meshes.Count; i++)
            {
                meshes[i].physics.mass = totalMassKg * (float)(meshes[i].physics.mass / totalDefaultMass);
            }
        }

        // Add meshes to all nodes
        for (int i = 0; i < meshes.Count; i++)
        {
            ((OGL_RigidNode)nodes[i]).loadMeshes(meshes[i]);
        }

        // Get wheel information (radius, center, etc.) for all wheels
        foreach (RigidNode_Base node in nodes)
        {
            SkeletalJoint_Base joint = node.GetSkeletalJoint();

            // Joint will be null if the node has no connection.
            // cDriver will be null if there is no driver connected to the joint.
            if (joint != null && joint.cDriver != null)
            {
                WheelDriverMeta wheelDriver = (WheelDriverMeta)joint.cDriver.GetInfo(typeof(WheelDriverMeta));

                // Drivers without wheel metadata do not need radius, center, or width info.
                if (wheelDriver != null)
                {
                    (node as OGLViewer.OGL_RigidNode).GetWheelInfo(out float radius, out float width, out BXDVector3 center);
                    wheelDriver.radius = radius;
                    wheelDriver.center = center;
                    wheelDriver.width  = width;

                    joint.cDriver.AddInfo(wheelDriver);
                }
            }
        }

        return(meshes);
    }