private static PosRot GetTrackerWorldPosRot(XRNodeState tracker) { Vector3 pos = new Vector3(); Quaternion rot = new Quaternion(); try { var notes = new List <XRNodeState>(); InputTracking.GetNodeStates(notes); foreach (XRNodeState note in notes) { if (note.uniqueID != tracker.uniqueID) { continue; } if (note.TryGetPosition(out pos) && note.TryGetRotation(out rot)) { var roomCenter = BeatSaberUtil.GetRoomCenter(); var roomRotation = BeatSaberUtil.GetRoomRotation(); pos = roomRotation * pos; pos += roomCenter; rot = roomRotation * rot; } } } catch (Exception e) { Logger.Log(e.Message + "\n" + e.StackTrace, Logger.LogLevel.Error); } return(new PosRot(pos, rot)); }
private void SetCameraCullingMask(Camera camera) { Logger.Log("Adding third person culling mask to " + camera.name); camera.cullingMask &= ~(1 << AvatarLayers.OnlyInThirdPerson); camera.cullingMask |= 1 << AvatarLayers.OnlyInFirstPerson; }
public static SpawnedAvatar SpawnAvatar(CustomAvatar customAvatar, IAvatarInput avatarInput) { if (customAvatar.GameObject == null) { Logger.Log("Can't spawn " + customAvatar.FullPath + " because it hasn't been loaded!"); return(null); } var avatarGameObject = Object.Instantiate(customAvatar.GameObject); var behaviour = avatarGameObject.AddComponent <AvatarBehaviour>(); behaviour.Init(avatarInput); avatarGameObject.AddComponent <AvatarEventsPlayer>(); /* Don't have the patience to make this work rn * * var mainCamera = Camera.main; * * foreach (Camera cam in avatarGameObject.GetComponentsInChildren<Camera>()) * { * if(mainCamera) * { * var newCamObj = Object.Instantiate(mainCamera, cam.transform); * newCamObj.tag = "Untagged"; * while (newCamObj.transform.childCount > 0) Object.DestroyImmediate(newCamObj.transform.GetChild(0).gameObject); * Object.DestroyImmediate(newCamObj.GetComponent("CameraRenderCallbacksManager")); * Object.DestroyImmediate(newCamObj.GetComponent("AudioListener")); * Object.DestroyImmediate(newCamObj.GetComponent("MeshCollider")); * * var newCam = newCamObj.GetComponent<Camera>(); * newCam.stereoTargetEye = StereoTargetEyeMask.None; * newCam.cullingMask = cam.cullingMask; * * var _liv = newCam.GetComponent<LIV.SDK.Unity.LIV>(); * if (_liv) * Object.Destroy(_liv); * * var _screenCamera = new GameObject("Screen Camera").AddComponent<ScreenCameraBehaviour>(); * * if (_previewMaterial == null) * _previewMaterial = new Material(Shader.Find("Hidden/BlitCopyWithDepth")); * * * cam.enabled = false; * } * } */ Object.DontDestroyOnLoad(avatarGameObject); var spawnedAvatar = new SpawnedAvatar(customAvatar, avatarGameObject); return(spawnedAvatar); }
public void OnSceneTransitioned(Scene newScene) { Logger.Log("OnSceneTransitioned - " + newScene.name); if (newScene.name.Equals("GameCore")) { _currentSpawnedPlayerAvatar?.GameObject.GetComponentInChildren <AvatarEventsPlayer>()?.LevelStartedEvent(); } else if (newScene.name.Equals("MenuCore")) { _currentSpawnedPlayerAvatar?.GameObject.GetComponentInChildren <AvatarEventsPlayer>()?.MenuEnteredEvent(); } }
TableCell TableView.IDataSource.CellForIdx(int row) { LevelListTableCell tableCell = _tableView.DequeueReusableCellForIdentifier("AvatarListCell") as LevelListTableCell; if (tableCell == null) { tableCell = Instantiate(_tableCellTemplate); // remove level type icons tableCell.transform.Find("LevelTypeIcon0").gameObject.SetActive(false); tableCell.transform.Find("LevelTypeIcon1").gameObject.SetActive(false); tableCell.transform.Find("LevelTypeIcon2").gameObject.SetActive(false); tableCell.reuseIdentifier = "AvatarListCell"; } var cellInfo = new AvatarCellInfo(); if (__AvatarLoadResults[row] != AvatarLoadResult.Completed) { cellInfo.name = System.IO.Path.GetFileName(AvatarList[row].FullPath) + " failed to load"; cellInfo.authorName = "Make sure it's not a duplicate avatar."; cellInfo.rawImageTexture = null; } else { try { cellInfo.name = __AvatarNames[row]; cellInfo.authorName = __AvatarAuthors[row]; cellInfo.rawImageTexture = __AvatarCovers[row] ? __AvatarCovers[row].texture : Texture2D.blackTexture; } catch (Exception e) { cellInfo.name = "If you see this yell at Assistant"; cellInfo.authorName = "because she f****d up"; cellInfo.rawImageTexture = Texture2D.blackTexture; Logger.Log(e.StackTrace, Logger.LogLevel.Error); } } tableCell.SetPrivateField("_beatmapCharacteristicAlphas", new float[0]); tableCell.SetPrivateField("_beatmapCharacteristicImages", new UnityEngine.UI.Image[0]); tableCell.GetPrivateField <TextMeshProUGUI>("_songNameText").text = cellInfo.name; tableCell.GetPrivateField <TextMeshProUGUI>("_authorText").text = cellInfo?.authorName; tableCell.GetPrivateField <UnityEngine.UI.RawImage>("_coverRawImage").texture = cellInfo.rawImageTexture; return(tableCell); }
private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (scene.name == "MenuCore") { if (Plugin.Instance.AvatarLoader.Avatars.Count == 0) { Logger.Log("[CustomAvatarsPlugin] No avatars found. Button not created."); } else { AddMainButton(); Logger.Log("[CustomAvatarsPlugin] Creating Avatars Button."); } } }
public void OnUpdate() { if (Input.GetKeyDown(KeyCode.PageDown)) { PlayerAvatarManager?.SwitchToNextAvatar(); } else if (Input.GetKeyDown(KeyCode.PageUp)) { PlayerAvatarManager?.SwitchToPreviousAvatar(); } else if (Input.GetKeyDown(KeyCode.Home)) { FirstPersonEnabled = !FirstPersonEnabled; } else if (Input.GetKeyDown(KeyCode.F6)) { IsTrackerAsHand = !IsTrackerAsHand; } else if (Input.GetKeyDown(KeyCode.F5)) { IsFullBodyTracking = !IsFullBodyTracking; } else if (Input.GetKeyDown(KeyCode.End)) { int policy = (int)Plugin.Instance.AvatarTailor.ResizePolicy + 1; if (policy > 2) { policy = 0; } Plugin.Instance.AvatarTailor.ResizePolicy = (AvatarTailor.ResizePolicyType)policy; Logger.Log($"Set Resize Policy to {Plugin.Instance.AvatarTailor.ResizePolicy}"); Plugin.Instance.PlayerAvatarManager.ResizePlayerAvatar(); } else if (Input.GetKeyDown(KeyCode.Insert)) { if (Plugin.Instance.AvatarTailor.FloorMovePolicy == AvatarTailor.FloorMovePolicyType.AllowMove) { Plugin.Instance.AvatarTailor.FloorMovePolicy = AvatarTailor.FloorMovePolicyType.NeverMove; } else { Plugin.Instance.AvatarTailor.FloorMovePolicy = AvatarTailor.FloorMovePolicyType.AllowMove; } Logger.Log($"Set Floor Move Policy to {Plugin.Instance.AvatarTailor.FloorMovePolicy}"); Plugin.Instance.PlayerAvatarManager.ResizePlayerAvatar(); } }
public void SetVRTargets(Transform body, Transform head, Transform leftHand, Transform rightHand) { if (!(body && head && leftHand && rightHand)) { Logger.Log("Something went wrong - IK Targets not found for player"); Logger.Log("Body: " + body.name); Logger.Log("HeadTarget: " + head.name); Logger.Log("LeftHandTarget: " + leftHand.name); Logger.Log("RightHandTarget: " + rightHand.name); isValid = false; return; } _playerBody = body; _playerHead = head; _playerLeftHand = leftHand; _playerRightHand = rightHand; }
public void OnFirstPersonEnabledChanged(bool firstPersonEnabled) { try { Logger.Log("OnFirstPersonEnabledChanged - " + firstPersonEnabled); if (_deadSwitch) { return; } for (var i = 0; i < Exclude.Length; i++) { var excludeObject = Exclude[i]; excludeObject.layer = AvatarLayers.OnlyInThirdPerson; } } catch (System.Exception e) { Logger.Log(e.StackTrace); } }
private void AvatarsLoaded(IReadOnlyList <CustomAvatar> loadedAvatars) { if (loadedAvatars.Count == 0) { Logger.Log("No custom avatars found in path " + Path.GetFullPath(CustomAvatarsPath)); return; } var previousAvatarPath = PlayerPrefs.GetString(PreviousAvatarKey, null); if (!File.Exists(previousAvatarPath)) { previousAvatarPath = AvatarLoader.Avatars[0].FullPath; } var previousAvatar = AvatarLoader.Avatars.FirstOrDefault(x => x.FullPath == previousAvatarPath); PlayerAvatarManager = new PlayerAvatarManager(AvatarLoader, AvatarTailor, previousAvatar); PlayerAvatarManager.AvatarChanged += PlayerAvatarManagerOnAvatarChanged; IsFullBodyTracking = true; }
public void Init(GameObject avatarMirror) { Logger.Log("Begin Mirror Init"); _avatarMirror = avatarMirror; var _VRIK = _avatarMirror.GetComponentsInChildren <AvatarScriptPack.VRIK>().FirstOrDefault(); Logger.Log("Obtaining IK Targets for Mirror"); _head = _avatarMirror.transform.Find("Head/HeadTarget").transform; _leftHand = _avatarMirror.transform.Find("LeftHand/LeftHandTarget").transform; _rightHand = _avatarMirror.transform.Find("RightHand/RightHandTarget").transform; if (!(_head && _leftHand && _rightHand)) { Logger.Log("Something went wrong - IK Targets not found for mirror"); isValid = false; } Logger.Log("Setting IK Targets for mirror"); _VRIK.solver.spine.headTarget = _head.transform; _VRIK.solver.leftArm.target = _leftHand.transform; _VRIK.solver.rightArm.target = _rightHand.transform; }
private void CustomAvatarLoaded(CustomAvatar loadedAvatar, AvatarLoadResult result) { if (result != AvatarLoadResult.Completed) { Logger.Log("Avatar " + loadedAvatar.FullPath + " failed to load"); return; } Logger.Log("Loaded avatar " + loadedAvatar.Name + " by " + loadedAvatar.AuthorName); if (_currentSpawnedPlayerAvatar?.GameObject != null) { Object.Destroy(_currentSpawnedPlayerAvatar.GameObject); } _currentSpawnedPlayerAvatar = AvatarSpawner.SpawnAvatar(loadedAvatar, _playerAvatarInput); AvatarChanged?.Invoke(loadedAvatar); _avatarTailor.OnAvatarLoaded(_currentSpawnedPlayerAvatar); ResizePlayerAvatar(); OnFirstPersonEnabledChanged(Plugin.Instance.FirstPersonEnabled); }
private void LateUpdate() { try { var headPosRot = _avatarInput.HeadPosRot; var leftPosRot = _avatarInput.LeftPosRot; var rightPosRot = _avatarInput.RightPosRot; _head.position = headPosRot.Position; _head.rotation = headPosRot.Rotation; _leftHand.position = leftPosRot.Position; _leftHand.rotation = leftPosRot.Rotation; _rightHand.position = rightPosRot.Position; _rightHand.rotation = rightPosRot.Rotation; if (_leftLeg != null && _rightLeg != null && _avatarInput is IAvatarFullBodyInput) { var _fbinput = _avatarInput as IAvatarFullBodyInput; var leftLegPosRot = _fbinput.LeftLegPosRot; var rightLegPosRot = _fbinput.RightLegPosRot; _prevLeftLegPos = Vector3.Lerp(_prevLeftLegPos, leftLegPosRot.Position, 15 * Time.deltaTime); _prevLeftLegRot = Quaternion.Slerp(_prevLeftLegRot, leftLegPosRot.Rotation, 10 * Time.deltaTime); _leftLeg.position = _prevLeftLegPos; _leftLeg.rotation = _prevLeftLegRot; _prevRightLegPos = Vector3.Lerp(_prevRightLegPos, rightLegPosRot.Position, 15 * Time.deltaTime); _prevRightLegRot = Quaternion.Slerp(_prevRightLegRot, rightLegPosRot.Rotation, 10 * Time.deltaTime); _rightLeg.position = _prevRightLegPos; _rightLeg.rotation = _prevRightLegRot; } if (_pelvis != null && _avatarInput is IAvatarFullBodyInput) { var _fbinput = _avatarInput as IAvatarFullBodyInput; var pelvisPosRot = _fbinput.PelvisPosRot; _prevPelvisPos = Vector3.Lerp(_prevPelvisPos, pelvisPosRot.Position, 17 * Time.deltaTime); _prevPelvisRot = Quaternion.Slerp(_prevPelvisRot, pelvisPosRot.Rotation, 13 * Time.deltaTime); _pelvis.position = _prevPelvisPos; _pelvis.rotation = _prevPelvisRot; } var vrPlatformHelper = PersistentSingleton <VRPlatformHelper> .instance; vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_leftHand); vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_rightHand); if (_body == null) { return; } _body.position = _head.position - (_head.transform.up * 0.1f); var vel = new Vector3(_body.transform.localPosition.x - _prevBodyPos.x, 0.0f, _body.localPosition.z - _prevBodyPos.z); var rot = Quaternion.Euler(0.0f, _head.localEulerAngles.y, 0.0f); var tiltAxis = Vector3.Cross(gameObject.transform.up, vel); _body.localRotation = Quaternion.Lerp(_body.localRotation, Quaternion.AngleAxis(vel.magnitude * 1250.0f, tiltAxis) * rot, Time.deltaTime * 10.0f); _prevBodyPos = _body.transform.localPosition; } catch (Exception e) { Logger.Log($"{e.Message}\n{e.StackTrace}", Logger.LogLevel.Error); } }
public void LoadAllAvatars() { int _AvatarIndex = 0; __AvatarPrefabs = new GameObject[AvatarList.Count()]; __AvatarNames = new string[AvatarList.Count()]; __AvatarAuthors = new string[AvatarList.Count()]; __AvatarPaths = new string[AvatarList.Count()]; __AvatarCovers = new Sprite[AvatarList.Count()]; __AvatarLoadResults = new AvatarLoadResult[AvatarList.Count()]; for (int i = 0; i < AvatarList.Count(); i++) { _AvatarIndex = i; var avatar = AvatarList[_AvatarIndex]; try { #if DEBUG Logger.Log("AddToArray -> " + _AvatarIndex); #endif avatar.Load(AddToArray); #if DEBUG Logger.Log("AddToArray => " + _AvatarIndex + " (" + Plugin.Instance.AvatarLoader.IndexOf(avatar) + ") | " + avatar.FullPath); #endif } catch (Exception e) { #if DEBUG Logger.Log(_AvatarIndex + " | " + e); #endif } } void AddToArray(CustomAvatar avatar, AvatarLoadResult _loadResult) { #if DEBUG Logger.Log("AddToArray == " + AvatarLoadResult.Completed); #endif if (_loadResult != AvatarLoadResult.Completed) { Logger.Log("Avatar " + avatar.FullPath + " failed to load"); return; } AvatarIndex = Plugin.Instance.AvatarLoader.IndexOf(avatar); __AvatarNames[AvatarIndex] = avatar.Name; __AvatarAuthors[AvatarIndex] = avatar.AuthorName; __AvatarCovers[AvatarIndex] = avatar.CoverImage; __AvatarPaths[AvatarIndex] = avatar.FullPath; __AvatarPrefabs[AvatarIndex] = avatar.GameObject; __AvatarLoadResults[AvatarIndex] = _loadResult; _loadedCount++; #if DEBUG Logger.Log("(" + _loadedCount + "/" + ((int)AvatarList.Count()) + ") #" + AvatarIndex); #endif //if (_loadedCount == (AvatarList.Count())) if (true) { _tableView.ReloadData(); PreviewCurrent(); } } }
private void FirstActivation() { RectTransform containerRect = new GameObject("AvatarSettingsContainer", typeof(RectTransform)).transform as RectTransform; containerRect.SetParent(rectTransform, false); containerRect.anchorMin = new Vector2(0.05f, 0.0f); containerRect.anchorMax = new Vector2(0.95f, 1.0f); containerRect.sizeDelta = new Vector2(0, 0); SubMenu container = new SubMenu(containerRect); List <ListViewController> loadedSettings = new List <ListViewController>(); System.Action <RectTransform, float, float, float, float, float, float> relative_layout = (RectTransform rt, float x, float y, float w, float h, float pivotx, float pivoty) => { rt.anchorMin = new Vector2(x, y); rt.anchorMax = new Vector2(x + w, y + h); rt.pivot = new Vector2(pivotx, pivoty); rt.sizeDelta = Vector2.zero; rt.anchoredPosition = Vector2.zero; }; gameObject.SetActive(false); TextMeshProUGUI text = BeatSaberUI.CreateText(containerRect, "AVATAR SETTINGS (Klouder is cute)", Vector2.zero); text.fontSize = 6.0f; text.alignment = TextAlignmentOptions.Center; relative_layout(text.rectTransform, 0f, 0.85f, 1f, 0.166f, 0.5f, 1f); var boolFirstPerson = container.AddList("Visible In First Person View", new float[] { 0, 1 }); boolFirstPerson.applyImmediately = true; relative_layout(boolFirstPerson.transform as RectTransform, 0, 0.66f, 1, 0.166f, 0, 1f); BeatSaberUI.AddHintText(boolFirstPerson.transform as RectTransform, "Allows you to see the avatar inside of VR"); var listResizePolicy = container.AddList("Resize Avatars To Player's", new float[] { 0, 1, 2 }); listResizePolicy.applyImmediately = true; relative_layout(listResizePolicy.transform as RectTransform, 0, 0.55f, 1, 0.166f, 0, 1f); BeatSaberUI.AddHintText(listResizePolicy.transform as RectTransform, "Use 'Arms Length' to resize the avatar based on your proportions, 'Height' to resize based on your height, and 'Never' to not resize"); var boolFloorMovePolicy = container.AddList("Floor Height Adjust", new float[] { 0, 1 }); boolFloorMovePolicy.applyImmediately = true; relative_layout(boolFloorMovePolicy.transform as RectTransform, 0, 0.44f, 1, 0.166f, 0, 1f); BeatSaberUI.AddHintText(boolFloorMovePolicy.transform as RectTransform, "Move the floor to compensate for height when using 'Arms Length' resize, requires CustomPlatforms"); var labelMeasure = BeatSaberUI.CreateText(containerRect, $"Hand To Hand Length = {Mathf.Ceil(Plugin.Instance.AvatarTailor.PlayerArmLength * 100.0f) / 100.0f}", Vector2.zero); relative_layout(labelMeasure.transform as RectTransform, 0f, 0.18f, 0.5f, 0.11f, 0, .5f); BeatSaberUI.AddHintText(labelMeasure.transform as RectTransform, "Value used for 'Arms Length' resize, press on the 'MEASURE!' button and T-Pose"); labelMeasure.fontSize = 5f; labelMeasure.alignment = TextAlignmentOptions.MidlineLeft; gameObject.SetActive(true); var buttonMeasure = BeatSaberUI.CreateUIButton(containerRect, "QuitButton", () => { labelMeasure.text = "Measuring ..."; Plugin.Instance.AvatarTailor.MeasurePlayerArmLength((value) => { labelMeasure.text = $"Measuring ... {Mathf.Ceil(value * 100.0f) / 100.0f}"; }, (result) => { labelMeasure.text = $"Hand To Hand Length = {Mathf.Ceil(result * 100.0f) / 100.0f}"; if (Plugin.Instance.AvatarTailor.ResizePolicy == AvatarTailor.ResizePolicyType.AlignArmLength) { Plugin.Instance.PlayerAvatarManager.ResizePlayerAvatar(); } }); }, "Measure!"); relative_layout(buttonMeasure.transform as RectTransform, 0.65f, 0.18f, 0.35f, 0.11f, .5f, .5f); BeatSaberUI.AddHintText(buttonMeasure.transform as RectTransform, "Press this and T-Pose to measure your arms, needed to use 'Arms Length' resize"); boolFirstPerson.GetTextForValue = (value) => (value != 0f) ? "ON" : "OFF"; boolFirstPerson.GetValue = () => Plugin.Instance.FirstPersonEnabled ? 1f : 0f; boolFirstPerson.SetValue = (value) => Plugin.Instance.FirstPersonEnabled = value != 0f; boolFirstPerson.Init(); loadedSettings.Add(boolFirstPerson); listResizePolicy.GetTextForValue = (value) => new string[] { "Arms Length", "Height", "Never" }[(int)value]; listResizePolicy.GetValue = () => (int)Plugin.Instance.AvatarTailor.ResizePolicy; listResizePolicy.SetValue = (value) => { Plugin.Instance.AvatarTailor.ResizePolicy = (AvatarTailor.ResizePolicyType)(int) value; Plugin.Instance.PlayerAvatarManager.ResizePlayerAvatar(); }; listResizePolicy.Init(); loadedSettings.Add(listResizePolicy); boolFloorMovePolicy.GetTextForValue = (value) => (value != 0f) ? "ON" : "OFF"; boolFloorMovePolicy.GetValue = () => Plugin.Instance.AvatarTailor.FloorMovePolicy == AvatarTailor.FloorMovePolicyType.AllowMove ? 1f : 0f; boolFloorMovePolicy.SetValue = (value) => { Plugin.Instance.AvatarTailor.FloorMovePolicy = (value != 0f) ? AvatarTailor.FloorMovePolicyType.AllowMove : AvatarTailor.FloorMovePolicyType.NeverMove; Plugin.Instance.PlayerAvatarManager.ResizePlayerAvatar(); }; boolFloorMovePolicy.Init(); loadedSettings.Add(boolFloorMovePolicy); foreach (ListViewController list in loadedSettings) { list.InvokePrivateMethod("OnDisable", new object[] { }); list.InvokePrivateMethod("OnEnable", new object[] { }); Logger.Log("Reset " + list.name); } }
IEnumerator SpawnMirror() { yield return(new WaitUntil(() => Camera.main)); mirrorCamObj = Instantiate(Camera.main.gameObject); mirrorCamObj.SetActive(false); mirrorCamObj.name = "mirrorCamObj"; mirrorCamObj.tag = "Untagged"; mirrorCamObj.transform.parent = null; while (mirrorCamObj.transform.childCount > 0) { DestroyImmediate(mirrorCamObj.transform.GetChild(0).gameObject); } DestroyImmediate(mirrorCamObj.GetComponent("CameraRenderCallbacksManager")); DestroyImmediate(mirrorCamObj.GetComponent("AudioListener")); DestroyImmediate(mirrorCamObj.GetComponent("MeshCollider")); _cam = mirrorCamObj.GetComponent <Camera>(); _cam.stereoTargetEye = StereoTargetEyeMask.None; _cam.enabled = true; _cam.orthographic = true; _cam.aspect = 1.4f; _cam.orthographicSize = 1.25f; _cam.clearFlags = CameraClearFlags.SolidColor; _cam.backgroundColor = new Color(0, 0, 0, 5 / 255f); _cam.farClipPlane = 10; int layer1 = 3; int layer2 = 4; int layer3 = 0; int layerMask1 = 1 << layer1; int layerMask2 = 1 << layer2; int layerMask3 = 1 << layer3; int finalMask = layerMask1 | layerMask2 | layerMask3; _cam.cullingMask = finalMask; var _liv = _cam.GetComponent <LIV.SDK.Unity.LIV>(); if (_liv) { Destroy(_liv); } mirrorCamObj.SetActive(true); mirrorCamObj.transform.position = new Vector3(0, 1.25f, 1.45f); mirrorCamObj.transform.rotation = Quaternion.Euler(0, 180, 0); _camRenderTexture = new RenderTexture(1, 1, 24); _camRenderTexture.width = _cam.pixelWidth; _camRenderTexture.height = _cam.pixelHeight; _camRenderTexture.useDynamicScale = false; _camRenderTexture.Create(); _cam.targetTexture = _camRenderTexture; _mirrorMaterial = new Material(CutoutShader); _mirrorMaterial.SetTexture("_Tex", _camRenderTexture); _mirrorMaterial.SetFloat("_Cutout", .01f); _quad = GameObject.CreatePrimitive(PrimitiveType.Quad); DontDestroyOnLoad(_quad); DestroyImmediate(_quad.GetComponent <Collider>()); _quad.GetComponent <MeshRenderer>().material = _mirrorMaterial; _quad.transform.parent = mirrorCamObj.transform; _quad.transform.localPosition = new Vector3(0, 0, -.05f); _quad.transform.localEulerAngles = new Vector3(0, 0, 0); _quad.transform.localScale = new Vector3(2.5f * _cam.aspect, 2.5f, 2.5f); Logger.Log($"Mirror Resolution: {_cam.pixelWidth}x{_cam.pixelHeight}"); }