ppo-Pyramids-Training / Project /Assets /ML-Agents /Examples /SharedAssets /Scripts /ModelCarousel.cs
| using System; | |
| using System.Collections.Generic; | |
| using System.Text.RegularExpressions; | |
| using TMPro; | |
| using Unity.Barracuda; | |
| using Unity.MLAgents; | |
| using Unity.MLAgents.Policies; | |
| using UnityEditor; | |
| using UnityEditor.Recorder; | |
| using UnityEngine; | |
| /** | |
| * Usage Notes: | |
| * | |
| * Add onnx models to the list and they will be played sequentially. | |
| * Create a recorder and a video of the sequence will be captured automatically if "Auto Record" is selected. | |
| * Recording only works in the Editor (not in standalone build) | |
| * Create a TextMeshPro Text GameObject and attach it to have the number of training steps of the current model shown. | |
| * To manually control transition between models choose a very large time, or "Pause" the system, | |
| * then use "Force Next" to advance. | |
| * "Reset" will start the sequence from the beginning again, use "Start" to proceed after resetting. | |
| * "Time Scale Override" can be set, "Seconds Between Switches" will decrease proportionally if you increase this | |
| * (i.e it represents simulated seconds between switches, not real time) | |
| */ | |
| public class ModelCarousel : MonoBehaviour | |
| { | |
| public bool m_Start = true; | |
| public bool m_Reset = false; | |
| public bool m_Pause = true; | |
| public bool m_ForceNext = false; | |
| public bool m_Loop = false; | |
| public bool m_AutoRecord = true; | |
| public bool m_ResetAgentOnModelChange = false; | |
| public int m_SecondsBetweenSwitches = 10; | |
| public float m_TimeScaleOverride = 0.0f; | |
| public List<NNModel> m_Models = new List<NNModel>(); | |
| public bool m_ShowStepNumber = true; | |
| public int m_StepNumberRounding = 10000; | |
| private int m_StepsSinceLastSwitch = 0; | |
| private int m_CurrentModelIndex = 0; | |
| private int m_CurrentlySetModelIndex = -1; | |
| private NNModel m_OriginalModel = null; | |
| private int k_FixedUpdatePerSecond; | |
| // The attached Agent | |
| Agent m_Agent; | |
| public TextMeshProUGUI textMeshComponent; | |
| private RecorderWindow GetRecorderWindow() | |
| { | |
| return (RecorderWindow)EditorWindow.GetWindow(typeof(RecorderWindow)); | |
| } | |
| private void Reset() | |
| { | |
| m_Reset = false; | |
| m_StepsSinceLastSwitch = 0; | |
| m_CurrentModelIndex = 0; | |
| m_Agent.SetModel(m_OriginalModel.name, m_OriginalModel); | |
| textMeshComponent?.SetText("Ready to Start"); | |
| } | |
| private void OnEnable() | |
| { | |
| m_Agent = GetComponent<Agent>(); | |
| m_OriginalModel = m_Agent.GetComponent<BehaviorParameters>().Model; | |
| Reset(); | |
| k_FixedUpdatePerSecond = (int)(1.0f / Time.fixedDeltaTime); | |
| if (m_TimeScaleOverride > 0.0f) | |
| { | |
| Time.timeScale = m_TimeScaleOverride; | |
| } | |
| } | |
| void StartRecording() | |
| { | |
| if (!m_AutoRecord) | |
| return; | |
| Debug.Log("Starting Recording"); | |
| RecorderWindow recorderWindow = GetRecorderWindow(); | |
| if (!recorderWindow.IsRecording()) | |
| recorderWindow.StartRecording(); | |
| } | |
| void StopRecording() | |
| { | |
| if (!m_AutoRecord) | |
| return; | |
| Debug.Log("Stopping Recording"); | |
| RecorderWindow recorderWindow = GetRecorderWindow(); | |
| if (recorderWindow.IsRecording()) | |
| recorderWindow.StopRecording(); | |
| } | |
| void UpdateStepNumberText() | |
| { | |
| if (!m_ShowStepNumber) | |
| return; | |
| var result = Regex.Match(m_Models[m_CurrentModelIndex].name, @".*-(\d+)$"); | |
| string newText = ""; | |
| if (result.Success && result.Groups.Count > 0) | |
| { | |
| var steps = Int32.Parse(result.Groups[1].Captures[0].Value); | |
| int round = m_StepNumberRounding; | |
| steps += round / 2; | |
| steps /= round; | |
| steps *= round; | |
| newText = $"After {steps:n0} steps"; | |
| } | |
| textMeshComponent?.SetText(newText); | |
| } | |
| void SetModel() | |
| { | |
| if (m_CurrentModelIndex < 0 || m_CurrentModelIndex >= m_Models.Count) | |
| return; | |
| m_Agent.SetModel(m_Models[m_CurrentModelIndex].name, m_Models[m_CurrentModelIndex]); | |
| m_CurrentlySetModelIndex = m_CurrentModelIndex; | |
| UpdateStepNumberText(); | |
| if (m_ResetAgentOnModelChange) | |
| m_Agent.EndEpisode(); | |
| } | |
| void FixedUpdate() | |
| { | |
| if (m_Start) | |
| { | |
| m_Start = false; | |
| m_Pause = false; | |
| StartRecording(); | |
| } | |
| if (m_Reset) | |
| { | |
| StopRecording(); | |
| Reset(); | |
| m_Pause = true; | |
| m_Start = false; | |
| } | |
| if (m_Pause && !m_ForceNext) | |
| return; | |
| if (m_CurrentlySetModelIndex != m_CurrentModelIndex) | |
| { | |
| SetModel(); | |
| } | |
| m_StepsSinceLastSwitch++; | |
| if (m_StepsSinceLastSwitch >= m_SecondsBetweenSwitches * k_FixedUpdatePerSecond || m_ForceNext) | |
| { | |
| m_ForceNext = false; | |
| m_StepsSinceLastSwitch = 0; | |
| m_CurrentModelIndex++; | |
| if (m_CurrentModelIndex == m_Models.Count) | |
| { | |
| if (m_Loop) | |
| { | |
| m_CurrentModelIndex = 0; | |
| } | |
| else | |
| { | |
| Application.Quit(0); | |
| EditorApplication.isPlaying = false; | |
| return; | |
| } | |
| } | |
| SetModel(); | |
| } | |
| } | |
| } | |