From c09469a1f240d659786b176c56be4dc75db04102 Mon Sep 17 00:00:00 2001 From: mhby1g21 <mhby1g21@soton.ac.uk> Date: Sun, 29 Dec 2024 23:28:05 +0000 Subject: [PATCH] working spectator window, but following instead of same as main but stabilised --- ...plete XR Origin Set Up Variant AVVR.prefab | 240 ++++++++++++++++-- AVVR/Assets/_Scripts/DisplayManager.cs | 73 ++++++ AVVR/Assets/_Scripts/DisplayManager.cs.meta | 11 + AVVR/Assets/_Scripts/SpectatorCamera.cs | 130 ++++++++++ AVVR/Assets/_Scripts/SpectatorCamera.cs.meta | 11 + AVVR/Assets/_Scripts/SpectatorWindow.cs | 92 +++++++ AVVR/Assets/_Scripts/SpectatorWindow.cs.meta | 11 + 7 files changed, 543 insertions(+), 25 deletions(-) create mode 100644 AVVR/Assets/_Scripts/DisplayManager.cs create mode 100644 AVVR/Assets/_Scripts/DisplayManager.cs.meta create mode 100644 AVVR/Assets/_Scripts/SpectatorCamera.cs create mode 100644 AVVR/Assets/_Scripts/SpectatorCamera.cs.meta create mode 100644 AVVR/Assets/_Scripts/SpectatorWindow.cs create mode 100644 AVVR/Assets/_Scripts/SpectatorWindow.cs.meta diff --git a/AVVR/Assets/Prefabs/Complete XR Origin Set Up Variant AVVR.prefab b/AVVR/Assets/Prefabs/Complete XR Origin Set Up Variant AVVR.prefab index 25ce1d3..8ff51de 100644 --- a/AVVR/Assets/Prefabs/Complete XR Origin Set Up Variant AVVR.prefab +++ b/AVVR/Assets/Prefabs/Complete XR Origin Set Up Variant AVVR.prefab @@ -1,5 +1,184 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &3595680582673134672 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4075259292299637730} + - component: {fileID: 5742413650280917386} + m_Layer: 0 + m_Name: DisplayManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4075259292299637730 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3595680582673134672} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 2.5984073, y: 1.3109349, z: -0.265801} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8298045291338814965} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5742413650280917386 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3595680582673134672} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f86999510c81f1347962db37765a2031, type: 3} + m_Name: + m_EditorClassIdentifier: + xrCamera: {fileID: 7277802327414017196} + spectatorCamera: {fileID: 7249712585786564757} + useSecondaryWindow: 0 + windowSize: {x: 1920, y: 1080} + windowedMode: 1 +--- !u!1 &5619876154759688209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 24857229647593761} + - component: {fileID: 7249712585786564757} + - component: {fileID: 7321445143899016650} + - component: {fileID: 3450999096063229191} + - component: {fileID: 3027666375171427404} + m_Layer: 2 + m_Name: Spectator Camera + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &24857229647593761 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5619876154759688209} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8298045291338814965} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!20 &7249712585786564757 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5619876154759688209} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!81 &7321445143899016650 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5619876154759688209} + m_Enabled: 1 +--- !u!114 &3450999096063229191 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5619876154759688209} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: eeadcb6c2b1156149b5b7de36c38b5e0, type: 3} + m_Name: + m_EditorClassIdentifier: + xrOrigin: {fileID: 8298045291338814965} + xrCamera: {fileID: 7277802327414017193} + positionOffset: {x: 0, y: 0.5, z: -1} + rotationOffset: {x: 0, y: 0, z: 0} + positionSmoothTime: 0.15 + rotationSmoothTime: 0.15 + smoothRotation: 1 + smoothPosition: 1 + positionDamping: 0.5 + rotationDamping: 0.5 +--- !u!114 &3027666375171427404 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5619876154759688209} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fb47d93d4e6cb45498b98c41d9fc2b4c, type: 3} + m_Name: + m_EditorClassIdentifier: + enableWindowDrag: 1 + renderResolution: {x: 1920, y: 1080} --- !u!1001 &1865269505668036478 PrefabInstance: m_ObjectHideFlags: 0 @@ -78,23 +257,23 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 3582865935180742671, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3582865935180742671, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 3582865935180742671, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 352 objectReference: {fileID: 0} - target: {fileID: 3582865935180742671, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 200 objectReference: {fileID: 0} - target: {fileID: 3582865935180742671, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -111 objectReference: {fileID: 0} - target: {fileID: 4063634363251406371, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: SnapTurnProvider @@ -130,43 +309,43 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4843115453168706472, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 4843115453168706472, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 4843115453168706472, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 352 objectReference: {fileID: 0} - target: {fileID: 4843115453168706472, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 200 objectReference: {fileID: 0} - target: {fileID: 4843115453168706472, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -245 objectReference: {fileID: 0} - target: {fileID: 5233380041029087467, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 5233380041029087467, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 5233380041029087467, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 352 objectReference: {fileID: 0} - target: {fileID: 5233380041029087467, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 200 objectReference: {fileID: 0} - target: {fileID: 5233380041029087467, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -178 objectReference: {fileID: 0} - target: {fileID: 5603239251682444825, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.x @@ -210,23 +389,23 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 7559043828606092874, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 7559043828606092874, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 7559043828606092874, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 352 objectReference: {fileID: 0} - target: {fileID: 7559043828606092874, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 200 objectReference: {fileID: 0} - target: {fileID: 7559043828606092874, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -312 objectReference: {fileID: 0} - target: {fileID: 8027956442804198582, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_Value @@ -234,23 +413,23 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 9223145543918184230, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMax.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 9223145543918184230, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchorMin.y - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 9223145543918184230, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 352 objectReference: {fileID: 0} - target: {fileID: 9223145543918184230, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.x - value: 0 + value: 200 objectReference: {fileID: 0} - target: {fileID: 9223145543918184230, guid: d312efb32cfde1a4592787da1e12f8ec, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -44 objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] @@ -1160,6 +1339,12 @@ PrefabInstance: - targetCorrespondingSourceObject: {fileID: 1717954561962503726, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} insertIndex: -1 addedObject: {fileID: 536801052177267210} + - targetCorrespondingSourceObject: {fileID: 1717954561962503726, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} + insertIndex: -1 + addedObject: {fileID: 24857229647593761} + - targetCorrespondingSourceObject: {fileID: 1717954561962503726, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} + insertIndex: -1 + addedObject: {fileID: 4075259292299637730} - targetCorrespondingSourceObject: {fileID: 1767192434, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} insertIndex: -1 addedObject: {fileID: 5518899284880179292} @@ -1391,6 +1576,11 @@ MonoBehaviour: z: 0 radius: 0 mProbeBatchesUsed: [] +--- !u!20 &7277802327414017196 stripped +Camera: + m_CorrespondingSourceObject: {fileID: 1767192439, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} + m_PrefabInstance: {fileID: 7277802326999645147} + m_PrefabAsset: {fileID: 0} --- !u!4 &7277802327528778794 stripped Transform: m_CorrespondingSourceObject: {fileID: 1670256625, guid: f6336ac4ac8b4d34bc5072418cdc62a0, type: 3} diff --git a/AVVR/Assets/_Scripts/DisplayManager.cs b/AVVR/Assets/_Scripts/DisplayManager.cs new file mode 100644 index 0000000..43d1893 --- /dev/null +++ b/AVVR/Assets/_Scripts/DisplayManager.cs @@ -0,0 +1,73 @@ +using UnityEngine; +using UnityEngine.XR; +using System.Linq; + +public class DisplayManager : MonoBehaviour +{ + [Header("Camera References")] + [SerializeField] private Camera xrCamera; + [SerializeField] private Camera spectatorCamera; + + [Header("Display Settings")] + [SerializeField] private bool useSecondaryWindow = false; + [SerializeField] private Vector2Int windowSize = new Vector2Int(1920, 1080); + [SerializeField] private bool windowedMode = true; + + private void Start() + { + if (xrCamera == null || spectatorCamera == null) + { + Debug.LogError("Camera references not set in Display Manager!"); + return; + } + + SetupDisplays(); + } + + private void SetupDisplays() + { + // Configure XR Camera + xrCamera.targetDisplay = 0; // VR Display + + if (useSecondaryWindow) + { + CreateSecondaryWindow(); + } + else + { + // Use main display for spectator view + spectatorCamera.targetDisplay = 0; + xrCamera.depth = 0; + spectatorCamera.depth = 1; // Ensure spectator camera renders over XR camera on desktop + } + + // Set up spectator camera to not render to the VR display + spectatorCamera.stereoTargetEye = StereoTargetEyeMask.None; + } + + private void CreateSecondaryWindow() + { +#if UNITY_STANDALONE_WIN || UNITY_EDITOR + // Create a secondary window + if (!UnityEngine.Display.displays.Any(d => d.active && d != UnityEngine.Display.main)) + { + if (UnityEngine.Display.displays.Length > 1) + { + UnityEngine.Display.displays[1].Activate(); + spectatorCamera.targetDisplay = 1; + } + } +#endif + } + +#if UNITY_EDITOR + [UnityEditor.MenuItem("Window/Create Game View 2")] + public static void CreateSecondGameView() + { + var assembly = typeof(UnityEditor.EditorWindow).Assembly; + var gameViewType = assembly.GetType("UnityEditor.GameView"); + var gameView = UnityEditor.EditorWindow.GetWindow(gameViewType, false, "Game (Spectator)", true); + gameView.Show(); + } +#endif +} \ No newline at end of file diff --git a/AVVR/Assets/_Scripts/DisplayManager.cs.meta b/AVVR/Assets/_Scripts/DisplayManager.cs.meta new file mode 100644 index 0000000..103f9f2 --- /dev/null +++ b/AVVR/Assets/_Scripts/DisplayManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f86999510c81f1347962db37765a2031 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AVVR/Assets/_Scripts/SpectatorCamera.cs b/AVVR/Assets/_Scripts/SpectatorCamera.cs new file mode 100644 index 0000000..3e4eebf --- /dev/null +++ b/AVVR/Assets/_Scripts/SpectatorCamera.cs @@ -0,0 +1,130 @@ +using UnityEngine; +using UnityEngine.XR; + +[RequireComponent(typeof(Camera))] +public class SpectatorCamera : MonoBehaviour +{ + [Header("Target Settings")] + [SerializeField] private Transform xrOrigin; + [SerializeField] private Transform xrCamera; + [SerializeField] private Vector3 positionOffset = new Vector3(0f, 0.5f, -1f); + [SerializeField] private Vector3 rotationOffset; + + [Header("Smoothing")] + [SerializeField] private float positionSmoothTime = 0.15f; + [SerializeField] private float rotationSmoothTime = 0.15f; + [SerializeField] private bool smoothRotation = true; + [SerializeField] private bool smoothPosition = true; + + [Header("Damping")] + [Range(0f, 1f)] + [SerializeField] private float positionDamping = 0.5f; + [Range(0f, 1f)] + [SerializeField] private float rotationDamping = 0.5f; + + // Internal tracking variables + private Vector3 currentVelocity; + private Vector3 currentAngularVelocity; + private Vector3 targetPosition; + private Quaternion targetRotation; + + private void Start() + { + if (xrOrigin == null || xrCamera == null) + { + Debug.LogError("XR Origin or Camera reference not set in Spectator Camera!"); + enabled = false; + return; + } + + // Initialize position and rotation + transform.position = xrCamera.position + xrCamera.TransformDirection(positionOffset); + transform.rotation = xrCamera.rotation * Quaternion.Euler(rotationOffset); + } + + private void LateUpdate() + { + UpdateTargetTransform(); + SmoothlyFollowTarget(); + } + + private void UpdateTargetTransform() + { + // Calculate target position with offset + targetPosition = xrCamera.position + xrCamera.TransformDirection(positionOffset); + + // Calculate target rotation with offset + targetRotation = xrCamera.rotation * Quaternion.Euler(rotationOffset); + } + + private void SmoothlyFollowTarget() + { + if (smoothPosition) + { + // Smooth position following + transform.position = Vector3.SmoothDamp( + transform.position, + targetPosition, + ref currentVelocity, + positionSmoothTime, + Mathf.Infinity, + Time.deltaTime + ); + } + else + { + transform.position = targetPosition; + } + + if (smoothRotation) + { + // Smooth rotation following + transform.rotation = SmoothDampQuaternion( + transform.rotation, + targetRotation, + ref currentAngularVelocity, + rotationSmoothTime + ); + } + else + { + transform.rotation = targetRotation; + } + } + + // Custom quaternion smooth damp function + private Quaternion SmoothDampQuaternion(Quaternion current, Quaternion target, ref Vector3 currentVelocity, float smoothTime) + { + Vector3 currentEuler = current.eulerAngles; + Vector3 targetEuler = target.eulerAngles; + + // Ensure we rotate the shortest path + float deltaX = Mathf.DeltaAngle(currentEuler.x, targetEuler.x); + float deltaY = Mathf.DeltaAngle(currentEuler.y, targetEuler.y); + float deltaZ = Mathf.DeltaAngle(currentEuler.z, targetEuler.z); + + Vector3 targetAngles = currentEuler + new Vector3(deltaX, deltaY, deltaZ); + + Vector3 smoothedEuler = Vector3.SmoothDamp( + currentEuler, + targetAngles, + ref currentVelocity, + smoothTime, + Mathf.Infinity, + Time.deltaTime + ); + + return Quaternion.Euler(smoothedEuler); + } + + // Editor gizmos for visualization + private void OnDrawGizmosSelected() + { + if (xrCamera != null) + { + Gizmos.color = Color.green; + Gizmos.DrawWireSphere(xrCamera.position + xrCamera.TransformDirection(positionOffset), 0.1f); + Gizmos.DrawLine(xrCamera.position, xrCamera.position + xrCamera.TransformDirection(positionOffset)); + } + } +} \ No newline at end of file diff --git a/AVVR/Assets/_Scripts/SpectatorCamera.cs.meta b/AVVR/Assets/_Scripts/SpectatorCamera.cs.meta new file mode 100644 index 0000000..b8a14c9 --- /dev/null +++ b/AVVR/Assets/_Scripts/SpectatorCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eeadcb6c2b1156149b5b7de36c38b5e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AVVR/Assets/_Scripts/SpectatorWindow.cs b/AVVR/Assets/_Scripts/SpectatorWindow.cs new file mode 100644 index 0000000..dba9e90 --- /dev/null +++ b/AVVR/Assets/_Scripts/SpectatorWindow.cs @@ -0,0 +1,92 @@ +using UnityEngine; + +public class SpectatorWindow : MonoBehaviour +{ + private static SpectatorWindow instance; + private Camera spectatorCam; + private RenderTexture renderTexture; + private bool showWindow = true; + private Rect windowRect = new Rect(100, 100, 800, 450); + + [SerializeField] private bool enableWindowDrag = true; + [SerializeField] private Vector2Int renderResolution = new Vector2Int(1920, 1080); + + private void Awake() + { + if (instance == null) + { + instance = this; + DontDestroyOnLoad(gameObject); + } + else + { + Destroy(gameObject); + return; + } + + spectatorCam = GetComponent<Camera>(); + if (spectatorCam == null) + { + Debug.LogError("No camera attached to SpectatorWindow!"); + return; + } + + InitializeRenderTexture(); + } + + private void InitializeRenderTexture() + { + renderTexture = new RenderTexture(renderResolution.x, renderResolution.y, 24); + renderTexture.antiAliasing = 4; + spectatorCam.targetTexture = renderTexture; + } + + private void OnGUI() + { + if (!showWindow) return; + + // Draw the window + windowRect = enableWindowDrag ? + GUI.Window(0, windowRect, DrawWindowContents, "Spectator View") : + GUI.Window(0, windowRect, DrawWindowContents, ""); + } + + private void DrawWindowContents(int windowID) + { + // Draw the render texture + GUI.DrawTexture(new Rect(0, 20, windowRect.width, windowRect.height - 20), renderTexture); + + // Allow window dragging + if (enableWindowDrag) + { + GUI.DragWindow(); + } + + // Add a close button + if (GUI.Button(new Rect(windowRect.width - 25, 2, 20, 16), "X")) + { + showWindow = false; + } + } + + private void OnDestroy() + { + if (renderTexture != null) + { + renderTexture.Release(); + Destroy(renderTexture); + } + } + + // Public methods to control the window + public void ShowWindow() => showWindow = true; + public void HideWindow() => showWindow = false; + public void ToggleWindow() => showWindow = !showWindow; + + // Method to change window size + public void SetWindowSize(float width, float height) + { + windowRect.width = width; + windowRect.height = height; + } +} \ No newline at end of file diff --git a/AVVR/Assets/_Scripts/SpectatorWindow.cs.meta b/AVVR/Assets/_Scripts/SpectatorWindow.cs.meta new file mode 100644 index 0000000..8748a50 --- /dev/null +++ b/AVVR/Assets/_Scripts/SpectatorWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb47d93d4e6cb45498b98c41d9fc2b4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- GitLab