using TMPro; using UnityEditor; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using UnityEngine.Video; using InteractiveVideo.Examples; namespace InteractiveVideo.Editor { /// /// GameObject > Interactive Video > Create Example Setup /// Builds the whole example hierarchy in the open scene and wires every reference, so the only manual steps /// are dropping a VideoClip on the VideoPlayer and (optionally) swapping the sample tracking JSON. /// public static class InteractiveVideoSetupMenu { private const string Root = "Assets/InteractiveVideo/"; private const string HighlightMaterialPath = Root + "Materials/InteractiveVideoHighlight.mat"; private const string MaskMaterialPath = Root + "Materials/InteractiveVideoMask.mat"; private const string SampleJsonPath = Root + "Examples/tracking_sample.json"; [MenuItem("GameObject/Interactive Video/Create Example Setup", false, 10)] public static void CreateExampleSetup() { var highlightMat = AssetDatabase.LoadAssetAtPath(HighlightMaterialPath); var maskMat = AssetDatabase.LoadAssetAtPath(MaskMaterialPath); var sampleJson = AssetDatabase.LoadAssetAtPath(SampleJsonPath); if (highlightMat == null || maskMat == null) Debug.LogWarning($"[InteractiveVideo] Materials not found under {Root}Materials. Assign them by hand on the Highlight Controller / Mask Renderer."); // ---- EventSystem ---- if (Object.FindAnyObjectByType() == null) { var es = new GameObject("EventSystem", typeof(EventSystem)); #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER var moduleType = System.Type.GetType("UnityEngine.InputSystem.UI.InputSystemUIInputModule, Unity.InputSystem"); if (moduleType != null) es.AddComponent(moduleType); else es.AddComponent(); #else es.AddComponent(); #endif Undo.RegisterCreatedObjectUndo(es, "Create EventSystem"); } // ---- Canvas ---- var canvasGo = new GameObject("InteractiveVideoCanvas", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster)); Undo.RegisterCreatedObjectUndo(canvasGo, "Create Interactive Video Setup"); var canvas = canvasGo.GetComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; var scaler = canvasGo.GetComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); scaler.matchWidthOrHeight = 0.5f; // ---- System object: VideoPlayer + our components ---- var systemGo = new GameObject("InteractiveVideo", typeof(VideoPlayer), typeof(InteractiveVideoPlayer), typeof(VideoTrackingManager), typeof(PolygonMaskRenderer), typeof(VideoHighlightController)); Undo.RegisterCreatedObjectUndo(systemGo, "Create Interactive Video Setup"); var videoPlayer = systemGo.GetComponent(); videoPlayer.playOnAwake = false; videoPlayer.renderMode = VideoRenderMode.RenderTexture; videoPlayer.isLooping = true; videoPlayer.audioOutputMode = VideoAudioOutputMode.Direct; var ivPlayer = systemGo.GetComponent(); var tracking = systemGo.GetComponent(); var mask = systemGo.GetComponent(); var highlight = systemGo.GetComponent(); // ---- Video RawImage (fills the canvas, letterboxing done by the shader) ---- var rawGo = new GameObject("VideoRawImage", typeof(RectTransform), typeof(CanvasRenderer), typeof(RawImage), typeof(VideoClickHandler)); rawGo.transform.SetParent(canvasGo.transform, false); Stretch(rawGo.GetComponent()); var rawImage = rawGo.GetComponent(); rawImage.color = Color.white; rawImage.raycastTarget = true; var click = rawGo.GetComponent(); // ---- Debug overlay (child of the RawImage) ---- var debugGo = new GameObject("TrackingDebugOverlay", typeof(RectTransform), typeof(CanvasRenderer), typeof(TrackingDebugOverlay)); debugGo.transform.SetParent(rawGo.transform, false); Stretch(debugGo.GetComponent()); var overlay = debugGo.GetComponent(); // ---- Info panel ---- var panelGo = new GameObject("InfoPanel", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter), typeof(VideoObjectInfoPanel)); panelGo.transform.SetParent(canvasGo.transform, false); var panelRt = panelGo.GetComponent(); panelRt.anchorMin = panelRt.anchorMax = new Vector2(0f, 1f); panelRt.pivot = new Vector2(0f, 1f); panelRt.anchoredPosition = new Vector2(24f, -24f); panelRt.sizeDelta = new Vector2(360f, 0f); panelGo.GetComponent().color = new Color(0f, 0f, 0f, 0.6f); panelGo.GetComponent().raycastTarget = false; var layout = panelGo.GetComponent(); layout.padding = new RectOffset(16, 16, 12, 12); layout.spacing = 4f; layout.childForceExpandHeight = false; layout.childControlHeight = true; layout.childControlWidth = true; panelGo.GetComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; var nameText = MakeText(panelGo.transform, "NameText", "Father", 36, FontStyles.Bold); var actionText = MakeText(panelGo.transform, "ActionText", "Drinking water", 26, FontStyles.Normal); var idText = MakeText(panelGo.transform, "TrackIdText", "person_01", 18, FontStyles.Italic); idText.color = new Color(1f, 1f, 1f, 0.6f); var confText = MakeText(panelGo.transform, "ConfidenceText", "97 %", 18, FontStyles.Normal); confText.color = new Color(1f, 1f, 1f, 0.6f); var infoPanel = panelGo.GetComponent(); // ---- Demo controls (bottom bar) ---- var barGo = new GameObject("DemoControls", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(HorizontalLayoutGroup), typeof(InteractiveVideoDemoControls)); barGo.transform.SetParent(canvasGo.transform, false); var barRt = barGo.GetComponent(); barRt.anchorMin = new Vector2(0f, 0f); barRt.anchorMax = new Vector2(1f, 0f); barRt.pivot = new Vector2(0.5f, 0f); barRt.anchoredPosition = Vector2.zero; barRt.sizeDelta = new Vector2(0f, 64f); barGo.GetComponent().color = new Color(0f, 0f, 0f, 0.5f); var hl = barGo.GetComponent(); hl.padding = new RectOffset(16, 16, 12, 12); hl.spacing = 12f; hl.childForceExpandWidth = false; hl.childForceExpandHeight = true; hl.childControlWidth = true; hl.childControlHeight = true; hl.childAlignment = TextAnchor.MiddleLeft; var playBtn = MakeButton(barGo.transform, "PlayPauseButton", "Play", 110f, out var playLabel); var slider = MakeSlider(barGo.transform, "Scrubber"); var frameLabel = MakeText(barGo.transform, "FrameLabel", "0 / 0", 20, FontStyles.Normal); frameLabel.gameObject.AddComponent().preferredWidth = 140f; frameLabel.alignment = TextAlignmentOptions.Center; var modeBtn = MakeButton(barGo.transform, "ModeButton", "DimBackgroundAndOutline", 280f, out var modeLabel); var toggle = MakeToggle(barGo.transform, "DebugToggle", "Debug"); var demo = barGo.GetComponent(); // ---- wire everything via SerializedObject (fields are private) ---- Set(ivPlayer, ("videoPlayer", videoPlayer), ("videoDisplay", rawImage), ("trackingManager", tracking), ("highlightController", highlight)); Set(tracking, ("trackingJson", sampleJson)); SetBool(tracking, "showTrackingDebug", true); Set(mask, ("maskMaterial", maskMat)); Set(highlight, ("trackingManager", tracking), ("maskRenderer", mask), ("videoDisplay", rawImage), ("highlightMaterial", highlightMat)); Set(click, ("player", ivPlayer), ("trackingManager", tracking)); Set(overlay, ("player", ivPlayer), ("trackingManager", tracking)); Set(infoPanel, ("trackingManager", tracking), ("nameText", nameText), ("actionText", actionText), ("trackIdText", idText), ("confidenceText", confText)); SetBool(infoPanel, "showConfidence", true); Set(demo, ("player", ivPlayer), ("trackingManager", tracking), ("highlightController", highlight), ("playPauseButton", playBtn), ("playPauseLabel", playLabel), ("scrubber", slider), ("frameLabel", frameLabel), ("modeButton", modeBtn), ("modeLabel", modeLabel), ("debugToggle", toggle)); Selection.activeGameObject = systemGo; Debug.Log("[InteractiveVideo] Example setup created. Assign a VideoClip (or URL) on the VideoPlayer of 'InteractiveVideo' and press Play."); } // ------------------------------------------------------------------ helpers private static void Stretch(RectTransform rt) { rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; } private static TMP_Text MakeText(Transform parent, string name, string text, float size, FontStyles style) { var go = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI)); go.transform.SetParent(parent, false); var t = go.GetComponent(); t.text = text; t.fontSize = size; t.fontStyle = style; t.color = Color.white; t.raycastTarget = false; t.textWrappingMode = TextWrappingModes.NoWrap; t.overflowMode = TextOverflowModes.Ellipsis; return t; } private static Button MakeButton(Transform parent, string name, string label, float width, out TMP_Text labelText) { var go = new GameObject(name, typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button), typeof(LayoutElement)); go.transform.SetParent(parent, false); go.GetComponent().color = new Color(1f, 1f, 1f, 0.15f); go.GetComponent().preferredWidth = width; labelText = MakeText(go.transform, "Label", label, 20, FontStyles.Normal); Stretch(labelText.rectTransform); labelText.alignment = TextAlignmentOptions.Center; return go.GetComponent