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