diff --git a/src/Cinematic/Cells/CamPathNodeCell.cs b/src/Cinematic/Cells/CamPathNodeCell.cs index ee14f46..2e2ca16 100644 --- a/src/Cinematic/Cells/CamPathNodeCell.cs +++ b/src/Cinematic/Cells/CamPathNodeCell.cs @@ -43,8 +43,11 @@ namespace UnityExplorer.UI.Panels ButtonRef copyFovButton = UIFactory.CreateButton(UIRoot, "Copy Camera FoV", "Copy Camera FoV"); UIFactory.SetLayoutElement(copyFovButton.GameObject, minWidth: 100, minHeight: 25, flexibleWidth: 9999); copyFovButton.OnClick += () => { - point.fov = FreeCamPanel.ourCamera.fieldOfView; - GetCamPathsPanel().controlPoints[index] = point; + Camera freecam = FreeCamPanel.GetFreecam(); + if (freecam != null) { + point.fov = freecam.fieldOfView; + GetCamPathsPanel().controlPoints[index] = point; + } }; ButtonRef moveToPointButton = UIFactory.CreateButton(UIRoot, "Move Cam to Node", "Move Cam to Node"); @@ -52,7 +55,7 @@ namespace UnityExplorer.UI.Panels moveToPointButton.OnClick += () => { FreeCamPanel.SetCameraRotation(point.rotation); FreeCamPanel.SetCameraPosition(point.position); - FreeCamPanel.ourCamera.fieldOfView = point.fov; + FreeCamPanel.SetFOV(point.fov); }; ButtonRef moveUpButton = UIFactory.CreateButton(UIRoot, "MoveUp", "▲"); diff --git a/src/Cinematic/Cells/LightCell.cs b/src/Cinematic/Cells/LightCell.cs index fe95920..ac404c5 100644 --- a/src/Cinematic/Cells/LightCell.cs +++ b/src/Cinematic/Cells/LightCell.cs @@ -29,7 +29,7 @@ namespace UnityExplorer.UI.Panels //Active toggle Toggle toggleLight; - GameObject toggleObj = UIFactory.CreateToggle(UIRoot, "UseGameCameraToggle", out toggleLight, out label); + GameObject toggleObj = UIFactory.CreateToggle(UIRoot, "ActivateLightToggle", out toggleLight, out label); UIFactory.SetLayoutElement(toggleObj, minHeight: 25, flexibleWidth: 9999); toggleLight.onValueChanged.AddListener(value => { light.SetActive(value); }); toggleLight.isOn = true; @@ -90,7 +90,7 @@ namespace UnityExplorer.UI.Panels } public static void CopyFreeCamTransform(GameObject obj){ - Camera freeCam = FreeCamPanel.ourCamera; + Camera freeCam = FreeCamPanel.GetFreecam(); if (freeCam != null) { obj.transform.position = freeCam.transform.position; diff --git a/src/Config/ConfigManager.cs b/src/Config/ConfigManager.cs index 277070e..8de4c8e 100644 --- a/src/Config/ConfigManager.cs +++ b/src/Config/ConfigManager.cs @@ -1,4 +1,5 @@ using UnityExplorer.UI; +using UnityExplorer.UI.Panels; namespace UnityExplorer.Config { @@ -31,7 +32,7 @@ namespace UnityExplorer.Config public static ConfigElement Reflection_Hide_NativeInfoPtrs; public static ConfigElement Auto_Scale_UI; - public static ConfigElement Default_Gameplay_Freecam; + public static ConfigElement Default_Freecam; public static ConfigElement Pause; public static ConfigElement Frameskip; public static ConfigElement Screenshot; @@ -185,9 +186,9 @@ namespace UnityExplorer.Config "Especially useful when running games in high resolutions and you are having a hard time reading the mods menu (requires restart).", true); - Default_Gameplay_Freecam = new("Default Gameplay Freecam", - "Turn this on if you want the default gameplay freecam toggle on the Freecam panel to be on on startup.", - false); + Default_Freecam = new("Default Freecam mode", + "Default type of freecam selected on startup.", + FreeCamPanel.FreeCameraType.New); Pause = new("Pause", "Toggle the pause of the game.", diff --git a/src/UI/Panels/CamPaths.cs b/src/UI/Panels/CamPaths.cs index 5ff5c1a..ae56dcc 100644 --- a/src/UI/Panels/CamPaths.cs +++ b/src/UI/Panels/CamPaths.cs @@ -107,7 +107,7 @@ namespace UnityExplorer.UI.Panels default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleWidth: 9999); - ButtonRef startButton = UIFactory.CreateButton(horiGroup, "Start", "►"); + ButtonRef startButton = UIFactory.CreateButton(horiGroup, "Start", "►", new Color(0.2f, 0.4f, 0.2f)); UIFactory.SetLayoutElement(startButton.GameObject, minWidth: 50, minHeight: 25); startButton.OnClick += StartButton_OnClick; @@ -115,7 +115,7 @@ namespace UnityExplorer.UI.Panels UIFactory.SetLayoutElement(pauseContinueButton.GameObject, minWidth: 50, minHeight: 25); pauseContinueButton.OnClick += TogglePause_OnClick; - ButtonRef stopButton = UIFactory.CreateButton(horiGroup, "Stop", "■"); + ButtonRef stopButton = UIFactory.CreateButton(horiGroup, "Stop", "■", new Color(0.4f, 0.2f, 0.2f)); UIFactory.SetLayoutElement(stopButton.GameObject, minWidth: 50, minHeight: 25); stopButton.ButtonText.fontSize = 20; stopButton.OnClick += Stop_OnClick; @@ -364,7 +364,7 @@ namespace UnityExplorer.UI.Panels CatmullRom.CatmullRomPoint point = new CatmullRom.CatmullRomPoint( FreeCamPanel.GetCameraPosition(), FreeCamPanel.GetCameraRotation(), - FreeCamPanel.ourCamera.fieldOfView + FreeCamPanel.GetFreecam().fieldOfView ); controlPoints.Add(point); diff --git a/src/UI/Panels/FreeCamPanel.cs b/src/UI/Panels/FreeCamPanel.cs index 123e8cc..ed5b9bb 100644 --- a/src/UI/Panels/FreeCamPanel.cs +++ b/src/UI/Panels/FreeCamPanel.cs @@ -18,6 +18,13 @@ namespace UnityExplorer.UI.Panels { public class FreeCamPanel : UEPanel { + public enum FreeCameraType { + New, + Gameplay, + Cloned, + ForcedMatrix, + } + public FreeCamPanel(UIBase owner) : base(owner) { try { @@ -38,9 +45,9 @@ namespace UnityExplorer.UI.Panels public override bool ShouldSaveActiveState => true; internal static bool inFreeCamMode; - internal static bool usingGameCamera; public static Camera ourCamera; public static Camera lastMainCamera; + public static Camera cameraMatrixOverrider; internal static FreeCamBehaviour freeCamScript; internal static CatmullRom.CatmullRomMover cameraPathMover; @@ -53,13 +60,15 @@ namespace UnityExplorer.UI.Panels internal static Vector3? currentUserCameraPosition; internal static Quaternion? currentUserCameraRotation; + internal static float currentUserCameraFov; internal static Vector3 previousMousePosition; internal static Vector3 lastSetCameraPosition; static ButtonRef startStopButton; - public static Toggle useGameCameraToggle; + public static Dropdown cameraTypeDropdown; + internal static FreeCameraType currentCameraType; public static Toggle blockFreecamMovementToggle; public static Toggle blockGamesInputOnFreecamToggle; static InputFieldRef positionInput; @@ -119,6 +128,7 @@ namespace UnityExplorer.UI.Panels { currentUserCameraPosition = currentMain.transform.position; currentUserCameraRotation = currentMain.transform.rotation; + currentUserCameraFov = currentMain.fieldOfView; } } else @@ -127,38 +137,90 @@ namespace UnityExplorer.UI.Panels static void SetupFreeCamera() { - if (useGameCameraToggle.isOn) + switch ((FreeCameraType)cameraTypeDropdown.value) { - if (!lastMainCamera) - { - ExplorerCore.LogWarning($"There is no previous Camera found, reverting to default Free Cam."); - useGameCameraToggle.isOn = false; - } - else - { - usingGameCamera = true; - ourCamera = lastMainCamera; - MaybeToggleCinemachine(false); - - // If the farClipPlaneValue is the default one try to use the one from the gameplay camera - if (farClipPlaneValue == 2000){ - farClipPlaneValue = ourCamera.farClipPlane; - farClipPlaneInput.Text = farClipPlaneValue.ToString(); - // Let the default farClipPlane value exceed the slider max value - if (farClipPlaneValue <= farClipPlaneSlider.maxValue) - farClipPlaneSlider.value = farClipPlaneValue; + case FreeCameraType.Gameplay: + if (!lastMainCamera) + { + ExplorerCore.LogWarning($"There is no previous Camera found, reverting to New Free Cam."); + cameraTypeDropdown.value = (int)FreeCameraType.New; } - } - } - - if (!useGameCameraToggle.isOn) - { - usingGameCamera = false; - - if (lastMainCamera) - lastMainCamera.enabled = false; + else + { + currentCameraType = FreeCameraType.Gameplay; + ourCamera = lastMainCamera; + MaybeToggleCinemachine(false); + + // If the farClipPlaneValue is the default one try to use the one from the gameplay camera + if (farClipPlaneValue == 2000){ + farClipPlaneValue = ourCamera.farClipPlane; + farClipPlaneInput.Text = farClipPlaneValue.ToString(); + // Let the default farClipPlane value exceed the slider max value + if (farClipPlaneValue <= farClipPlaneSlider.maxValue) + farClipPlaneSlider.value = farClipPlaneValue; + } + } + break; + case FreeCameraType.New: + currentCameraType = FreeCameraType.New; + + if (lastMainCamera){ + lastMainCamera.enabled = false; + } + + ourCamera = new GameObject("UE_Freecam").AddComponent(); + ourCamera.gameObject.tag = "MainCamera"; + GameObject.DontDestroyOnLoad(ourCamera.gameObject); + ourCamera.gameObject.hideFlags = HideFlags.HideAndDontSave; + + break; + case FreeCameraType.Cloned: + if (!lastMainCamera) + { + ExplorerCore.LogWarning($"There is no previous Camera found, reverting to New Free Cam."); + cameraTypeDropdown.value = (int)FreeCameraType.New; + } else { + currentCameraType = FreeCameraType.Cloned; + + ourCamera = GameObject.Instantiate(lastMainCamera); + lastMainCamera.enabled = false; + MaybeToggleCinemachine(false); + + // If the farClipPlaneValue is the default one try to use the one from the gameplay camera + if (farClipPlaneValue == 2000){ + farClipPlaneValue = ourCamera.farClipPlane; + farClipPlaneInput.Text = farClipPlaneValue.ToString(); + // Let the default farClipPlane value exceed the slider max value + if (farClipPlaneValue <= farClipPlaneSlider.maxValue) + farClipPlaneSlider.value = farClipPlaneValue; + } + } + break; + case FreeCameraType.ForcedMatrix: + if (!lastMainCamera) + { + ExplorerCore.LogWarning($"There is no previous Camera found, reverting to New Free Cam."); + cameraTypeDropdown.value = (int)FreeCameraType.New; + } else { + currentCameraType = FreeCameraType.ForcedMatrix; + ourCamera = lastMainCamera; + // HDRP might introduce problems when moving the camera when replacing the worldToCameraMatrix, + // so we will try to move the real camera as well. + MaybeToggleCinemachine(false); + + cameraMatrixOverrider = new GameObject("[CUE] Camera Matrix Overrider").AddComponent(); + cameraMatrixOverrider.enabled = false; + cameraMatrixOverrider.transform.position = lastMainCamera.transform.position; + cameraMatrixOverrider.transform.rotation = lastMainCamera.transform.rotation; + } + + break; + default: + ExplorerCore.LogWarning($"Error: Camera type not implemented"); + break; } + // Fallback in case we couldn't find the main camera for some reason if (!ourCamera) { ourCamera = new GameObject("UE_Freecam").AddComponent(); @@ -173,8 +235,9 @@ namespace UnityExplorer.UI.Panels if (!cameraPathMover) cameraPathMover = ourCamera.gameObject.AddComponent(); - ourCamera.transform.position = (Vector3)currentUserCameraPosition; - ourCamera.transform.rotation = (Quaternion)currentUserCameraRotation; + GetFreecam().transform.position = (Vector3)currentUserCameraPosition; + GetFreecam().transform.rotation = (Quaternion)currentUserCameraRotation; + SetFOV(currentUserCameraFov); ourCamera.gameObject.SetActive(true); ourCamera.enabled = true; @@ -191,18 +254,41 @@ namespace UnityExplorer.UI.Panels inFreeCamMode = false; connector?.UpdateFreecamStatus(false); - if (usingGameCamera) - { + switch(currentCameraType) { + case FreeCameraType.Gameplay: + MaybeToggleCinemachine(true); + ourCamera = null; - MaybeToggleCinemachine(true); - ourCamera = null; + if (lastMainCamera) + { + lastMainCamera.transform.position = originalCameraPosition; + lastMainCamera.transform.rotation = originalCameraRotation; + lastMainCamera.fieldOfView = originalCameraFOV; + } + break; + case FreeCameraType.New: + GameObject.Destroy(ourCamera.gameObject); + ourCamera = null; + break; + case FreeCameraType.Cloned: + GameObject.Destroy(ourCamera.gameObject); + ourCamera = null; + break; + case FreeCameraType.ForcedMatrix: + MaybeToggleCinemachine(true); + MethodInfo resetCullingMatrixMethod = typeof(Camera).GetMethod("ResetCullingMatrix", new Type[] {}); + resetCullingMatrixMethod.Invoke(ourCamera, null); - if (lastMainCamera) - { - lastMainCamera.transform.position = originalCameraPosition; - lastMainCamera.transform.rotation = originalCameraRotation; - lastMainCamera.fieldOfView = originalCameraFOV; - } + ourCamera.ResetWorldToCameraMatrix(); + ourCamera.ResetProjectionMatrix(); + ourCamera = null; + + GameObject.Destroy(cameraMatrixOverrider.gameObject); + cameraMatrixOverrider = null; + break; + default: + ExplorerCore.LogWarning($"Error: Camera type not implemented"); + break; } if (ourCamera) @@ -271,7 +357,7 @@ namespace UnityExplorer.UI.Panels if (connector != null && connector.IsActive) return; - lastSetCameraPosition = ourCamera.transform.position; + lastSetCameraPosition = GetFreecam().transform.position; positionInput.Text = ParseUtility.ToStringForInput(lastSetCameraPosition); } @@ -280,6 +366,11 @@ namespace UnityExplorer.UI.Panels ourCamera.nearClipPlane = nearClipPlaneValue; ourCamera.farClipPlane = farClipPlaneValue; } + + if (cameraMatrixOverrider) { + cameraMatrixOverrider.nearClipPlane = nearClipPlaneValue; + cameraMatrixOverrider.farClipPlane = farClipPlaneValue; + } } // ~~~~~~~~ UI construction / callbacks ~~~~~~~~ @@ -293,11 +384,22 @@ namespace UnityExplorer.UI.Panels AddSpacer(5); - GameObject toggleObj = UIFactory.CreateToggle(ContentRoot, "UseGameCameraToggle", out useGameCameraToggle, out Text useGameCameraText); - UIFactory.SetLayoutElement(toggleObj, minHeight: 25, flexibleWidth: 9999); - useGameCameraToggle.onValueChanged.AddListener(OnUseGameCameraToggled); - useGameCameraToggle.isOn = ConfigManager.Default_Gameplay_Freecam.Value; - useGameCameraText.text = "Use Game Camera?"; + GameObject CameraModeRow = UIFactory.CreateHorizontalGroup(ContentRoot, "CameraModeRow", false, false, true, true, 3, default, new(1, 1, 1, 0)); + + Text CameraMode = UIFactory.CreateLabel(CameraModeRow, "Camera Mode", "Camera Mode:"); + UIFactory.SetLayoutElement(CameraMode.gameObject, minWidth: 100, minHeight: 25); + + GameObject cameraTypeDropdownObj = UIFactory.CreateDropdown(CameraModeRow, "CameraType_Dropdown", out cameraTypeDropdown, null, 14, (idx) => { + if (inFreeCamMode) { + EndFreecam(); + BeginFreecam(); + } + }); + foreach (FreeCameraType type in Enum.GetValues(typeof(FreeCameraType)).Cast()) { + cameraTypeDropdown.options.Add(new Dropdown.OptionData(Enum.GetName(typeof(FreeCameraType), type))); + } + UIFactory.SetLayoutElement(cameraTypeDropdownObj, minHeight: 25, minWidth: 150); + cameraTypeDropdown.value = (int)ConfigManager.Default_Freecam.Value; AddSpacer(5); @@ -616,54 +718,67 @@ namespace UnityExplorer.UI.Panels return inFreeCamMode && blockGamesInputOnFreecamToggle.isOn; } + public static Camera GetFreecam(){ + if (currentCameraType == FreeCameraType.ForcedMatrix) return cameraMatrixOverrider; + return ourCamera; + } + // Getters and Setters for camera position and rotation public static Vector3 GetCameraPosition(bool isAbsolute = false){ - if (isAbsolute) return ourCamera.transform.position; + Camera freecam = GetFreecam(); + if (isAbsolute) return freecam.transform.position; if (followObject){ if (followRotationToggle.isOn){ - return Quaternion.Inverse(followObject.transform.rotation) * (ourCamera.transform.position - followObject.transform.position); + return Quaternion.Inverse(followObject.transform.rotation) * (freecam.transform.position - followObject.transform.position); } else { - return ourCamera.transform.position - followObject.transform.position; + return freecam.transform.position - followObject.transform.position; } } - return ourCamera.transform.position; + return freecam.transform.position; } public static Quaternion GetCameraRotation(bool isAbsolute = false){ - if (isAbsolute) return ourCamera.transform.rotation; - if (followObject && followRotationToggle.isOn) return Quaternion.Inverse(followObjectLastRotation) * ourCamera.transform.rotation; - return ourCamera.transform.rotation; + Camera freecam = GetFreecam(); + if (isAbsolute) return freecam.transform.rotation; + if (followObject && followRotationToggle.isOn) return Quaternion.Inverse(followObjectLastRotation) * freecam.transform.rotation; + return freecam.transform.rotation; } public static void SetCameraPosition(Vector3 newPosition, bool isAbsolute = false){ + Camera freecam = GetFreecam(); if (isAbsolute){ - ourCamera.transform.position = newPosition; + freecam.transform.position = newPosition; } else if (followObject){ if (followRotationToggle.isOn){ - ourCamera.transform.position = followObject.transform.rotation * newPosition + followObject.transform.position; + freecam.transform.position = followObject.transform.rotation * newPosition + followObject.transform.position; } else { - ourCamera.transform.position = newPosition + followObject.transform.position; + freecam.transform.position = newPosition + followObject.transform.position; } } else { - ourCamera.transform.position = newPosition; + freecam.transform.position = newPosition; } } public static void SetCameraRotation(Quaternion newRotation, bool isAbsolute = false){ + Camera freecam = GetFreecam(); if (isAbsolute){ - ourCamera.transform.rotation = newRotation; + freecam.transform.rotation = newRotation; } else if (followObject && followRotationToggle.isOn){ - ourCamera.transform.rotation = followObjectLastRotation * newRotation; + freecam.transform.rotation = followObjectLastRotation * newRotation; } else { - ourCamera.transform.rotation = newRotation; + freecam.transform.rotation = newRotation; } } + + public static void SetFOV(float newFOV){ + GetFreecam().fieldOfView = newFOV; + } } internal class FreeCamBehaviour : MonoBehaviour @@ -676,6 +791,9 @@ namespace UnityExplorer.UI.Panels public FreeCamBehaviour(IntPtr ptr) : base(ptr) { } #endif + private Action onBeforeRenderAction; + private Vector3 cachedPosition; + private Quaternion cachedRotation; internal void Update() { @@ -686,35 +804,88 @@ namespace UnityExplorer.UI.Panels FreeCamPanel.EndFreecam(); return; } - Transform transform = FreeCamPanel.ourCamera.transform; + Transform movingTransform = FreeCamPanel.GetFreecam().transform; if (!FreeCamPanel.blockFreecamMovementToggle.isOn && !FreeCamPanel.cameraPathMover.playingPath && FreeCamPanel.connector?.IsActive != true) { - ProcessInput(); + ProcessInput(movingTransform); } - if (FreeCamPanel.followObject != null){ + if (FreeCamPanel.followObject != null){ // position update - transform.position += FreeCamPanel.followObject.transform.position - FreeCamPanel.followObjectLastPosition; + movingTransform.position += FreeCamPanel.followObject.transform.position - FreeCamPanel.followObjectLastPosition; if (FreeCamPanel.followRotationToggle.isOn){ // rotation update Quaternion deltaRotation = FreeCamPanel.followObject.transform.rotation * Quaternion.Inverse(FreeCamPanel.followObjectLastRotation); - Vector3 offset = transform.position - FreeCamPanel.followObject.transform.position; - transform.position = transform.position - offset + deltaRotation * offset; - transform.rotation = deltaRotation * transform.rotation; + Vector3 offset = movingTransform.position - FreeCamPanel.followObject.transform.position; + movingTransform.position = movingTransform.position - offset + deltaRotation * offset; + movingTransform.rotation = deltaRotation * movingTransform.rotation; } FreeCamPanel.followObjectLastPosition = FreeCamPanel.followObject.transform.position; FreeCamPanel.followObjectLastRotation = FreeCamPanel.followObject.transform.rotation; } - FreeCamPanel.connector?.ExecuteCameraCommand(FreeCamPanel.ourCamera); + UpdateRelativeMatrix(); + UpdateRealCamera(); + + FreeCamPanel.connector?.ExecuteCameraCommand(FreeCamPanel.GetFreecam()); FreeCamPanel.UpdatePositionInput(); } } - internal void ProcessInput(){ + private void OnPreCull() + { + UpdateRelativeMatrix(); + UpdateRealCamera(); + } + + private void OnPreRender() + { + UpdateRelativeMatrix(); + UpdateRealCamera(); + } + + private void OnCameraPostRender() + { + UpdateRelativeMatrix(); + //RestoreRealCameraTransform(); + } + + private void LateUpdate() + { + UpdateRelativeMatrix(); + //RestoreRealCameraTransform(); + } + + internal void UpdateRelativeMatrix() { + if (FreeCamPanel.cameraMatrixOverrider != null){ + try + { + MethodInfo getStereoViewMatrixMethod = typeof(Camera).GetMethod("GetStereoViewMatrix"); + Matrix4x4 stereoViewMatrixOverrider = getStereoViewMatrixMethod.Invoke(FreeCamPanel.cameraMatrixOverrider, new object[] {0}).TryCast(); + MethodInfo setStereoViewMatrixMethod = typeof(Camera).GetMethod("SetStereoViewMatrix"); + setStereoViewMatrixMethod.Invoke(FreeCamPanel.ourCamera, new object[] {0, stereoViewMatrixOverrider}); + } + catch (Exception ex) { + ExplorerCore.LogWarning(ex); + } + + FreeCamPanel.ourCamera.worldToCameraMatrix = FreeCamPanel.cameraMatrixOverrider.worldToCameraMatrix; + + // Maybe I should use nonJitteredProjectionMatrix instead + FreeCamPanel.ourCamera.projectionMatrix = FreeCamPanel.cameraMatrixOverrider.projectionMatrix; + + // Could be optimized so to not look up cullingMatrixProperty each frame + PropertyInfo cullingMatrixProperty = typeof(Camera).GetProperty("cullingMatrix"); + Matrix4x4 cullingMatrixOverrider = cullingMatrixProperty.GetValue(FreeCamPanel.cameraMatrixOverrider, null).TryCast(); + MethodInfo setCullingMatrixMethod = cullingMatrixProperty.GetSetMethod(); + setCullingMatrixMethod.Invoke(FreeCamPanel.ourCamera, new object[] {cullingMatrixOverrider}); + } + } + + internal void ProcessInput(Transform transform){ FreeCamPanel.currentUserCameraPosition = transform.position; FreeCamPanel.currentUserCameraRotation = transform.rotation; @@ -793,20 +964,156 @@ namespace UnityExplorer.UI.Panels if (IInputManager.GetKey(ConfigManager.Decrease_FOV.Value)) { - FreeCamPanel.ourCamera.fieldOfView -= moveSpeed; + FreeCamPanel.GetFreecam().fieldOfView -= moveSpeed; } if (IInputManager.GetKey(ConfigManager.Increase_FOV.Value)) { - FreeCamPanel.ourCamera.fieldOfView += moveSpeed; + FreeCamPanel.GetFreecam().fieldOfView += moveSpeed; } if (IInputManager.GetKey(ConfigManager.Reset_FOV.Value)){ - FreeCamPanel.ourCamera.fieldOfView = FreeCamPanel.usingGameCamera ? FreeCamPanel.originalCameraFOV : 60; + FreeCamPanel.GetFreecam().fieldOfView = FreeCamPanel.currentCameraType == FreeCamPanel.FreeCameraType.New ? 60 : FreeCamPanel.originalCameraFOV; } FreeCamPanel.previousMousePosition = IInputManager.MousePosition; } + + // The following code forces the freecamcam to update before rendering a frame + protected virtual void Awake() + { + onBeforeRenderAction = () => { UpdateRelativeMatrix(); UpdateRealCamera(); }; + } + + protected virtual void OnEnable() + { +#if CPP + try + { + Application.add_onBeforeRender(onBeforeRenderAction); + } + catch (Exception exception) + { + ExplorerCore.LogWarning($"Failed to listen to BeforeRender: {exception}"); + } +#endif + // These doesn't exist for Unity <2017 nor when using HDRP + Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager"); + if (renderPipelineManagerType != null){ + EventInfo beginFrameRenderingEvent = renderPipelineManagerType.GetEvent("beginFrameRendering"); + if (beginFrameRenderingEvent != null) { + beginFrameRenderingEvent.AddEventHandler(null, OnBeforeEvent); + } + EventInfo endFrameRenderingEvent = renderPipelineManagerType.GetEvent("endFrameRendering"); + if (endFrameRenderingEvent != null) { + endFrameRenderingEvent.AddEventHandler(null, OnAfterEvent); + } + + EventInfo beginCameraRenderingEvent = renderPipelineManagerType.GetEvent("beginCameraRendering"); + if (beginCameraRenderingEvent != null) { + beginCameraRenderingEvent.AddEventHandler(null, OnBeforeEvent); + } + EventInfo endCameraRenderingEvent = renderPipelineManagerType.GetEvent("endCameraRendering"); + if (endCameraRenderingEvent != null) { + endCameraRenderingEvent.AddEventHandler(null, OnAfterEvent); + } + + EventInfo beginContextRenderingEvent = renderPipelineManagerType.GetEvent("beginContextRendering"); + if (beginContextRenderingEvent != null) { + beginContextRenderingEvent.AddEventHandler(null, OnBeforeEvent); + } + EventInfo endContextRenderingEvent = renderPipelineManagerType.GetEvent("endContextRendering"); + if (endContextRenderingEvent != null) { + endContextRenderingEvent.AddEventHandler(null, OnAfterEvent); + } + } + + EventInfo onBeforeRenderEvent = typeof(Application).GetEvent("onBeforeRender"); + if (onBeforeRenderEvent != null) { + onBeforeRenderEvent.AddEventHandler(null, onBeforeRenderAction); + } + } + + protected virtual void OnDisable() + { +#if CPP + try + { + Application.remove_onBeforeRender(onBeforeRenderAction); + } + catch (Exception exception) + { + ExplorerCore.LogWarning($"Failed to unlisten from BeforeRender: {exception}"); + } +#endif + // These doesn't exist for Unity <2017 nor when using HDRP + Type renderPipelineManagerType = ReflectionUtility.GetTypeByName("RenderPipelineManager"); + + if (renderPipelineManagerType != null){ + EventInfo beginFrameRenderingEvent = renderPipelineManagerType.GetEvent("beginFrameRendering"); + if (beginFrameRenderingEvent != null) { + beginFrameRenderingEvent.RemoveEventHandler(null, OnBeforeEvent); + } + EventInfo endFrameRenderingEvent = renderPipelineManagerType.GetEvent("endFrameRendering"); + if (endFrameRenderingEvent != null) { + endFrameRenderingEvent.RemoveEventHandler(null, OnAfterEvent); + } + + EventInfo beginCameraRenderingEvent = renderPipelineManagerType.GetEvent("beginCameraRendering"); + if (beginCameraRenderingEvent != null) { + beginCameraRenderingEvent.RemoveEventHandler(null, OnBeforeEvent); + } + EventInfo endCameraRenderingEvent = renderPipelineManagerType.GetEvent("endCameraRendering"); + if (endCameraRenderingEvent != null) { + endCameraRenderingEvent.RemoveEventHandler(null, OnAfterEvent); + } + + EventInfo beginContextRenderingEvent = renderPipelineManagerType.GetEvent("beginContextRendering"); + if (beginContextRenderingEvent != null) { + beginContextRenderingEvent.RemoveEventHandler(null, OnBeforeEvent); + } + EventInfo endContextRenderingEvent = renderPipelineManagerType.GetEvent("endContextRendering"); + if (endContextRenderingEvent != null) { + endContextRenderingEvent.RemoveEventHandler(null, OnAfterEvent); + } + } + + EventInfo onBeforeRenderEvent = typeof(Application).GetEvent("onBeforeRender"); + if (onBeforeRenderEvent != null) { + onBeforeRenderEvent.RemoveEventHandler(null, onBeforeRenderAction); + } + } + + private void OnBeforeEvent(object arg1, Camera[] arg2) + { + UpdateRelativeMatrix(); + UpdateRealCamera(); + } + + private void OnAfterEvent(object arg1, Camera[] arg2) + { + UpdateRelativeMatrix(); + //RestoreRealCameraTransform(); + } + + // HDRP matrix override ignores us moving the camera unfortunately, so we try to copy over the position of the camera matrix overrider. + protected void UpdateRealCamera() { + if (FreeCamPanel.cameraMatrixOverrider != null) { + cachedPosition = FreeCamPanel.ourCamera.transform.position; + FreeCamPanel.ourCamera.transform.position = FreeCamPanel.cameraMatrixOverrider.transform.position; + // We also try to update the rotation in case there are game shaders that use the real camera rotation + cachedRotation = FreeCamPanel.ourCamera.transform.rotation; + FreeCamPanel.ourCamera.transform.rotation = FreeCamPanel.cameraMatrixOverrider.transform.rotation; + } + } + + protected void RestoreRealCameraTransform() { + if (FreeCamPanel.cameraMatrixOverrider != null) { + FreeCamPanel.ourCamera.transform.position = cachedPosition; + FreeCamPanel.ourCamera.transform.rotation = cachedRotation; + } + UpdateRealCamera(); + } } // Dummy UI class to unlock the cursor when freecam is active but the UI is hidden diff --git a/src/UI/Widgets/CatmullRom.cs b/src/UI/Widgets/CatmullRom.cs index 74641d0..79a6679 100644 --- a/src/UI/Widgets/CatmullRom.cs +++ b/src/UI/Widgets/CatmullRom.cs @@ -183,7 +183,7 @@ namespace UnityExplorer.CatmullRom Vector3 camPos = FreeCamPanel.GetCameraPosition(); Quaternion camRot = FreeCamPanel.GetCameraRotation(); - return new CatmullRomPoint(camPos, camRot, FreeCamPanel.ourCamera.fieldOfView); + return new CatmullRomPoint(camPos, camRot, FreeCamPanel.GetFreecam().fieldOfView); } private void AdvanceMover(float dt){ @@ -238,14 +238,14 @@ namespace UnityExplorer.CatmullRom FreeCamPanel.SetCameraRotation(CatmullRomPoint.Vector4ToQuaternion(newRot)); FreeCamPanel.SetCameraPosition(FreeCamPanel.GetCameraPosition() + direction.position); - FreeCamPanel.ourCamera.fieldOfView += direction.fov * actual / room; + FreeCamPanel.SetFOV(FreeCamPanel.GetFreecam().fieldOfView + direction.fov * actual / room); } public void MoveCameraToPoint(CatmullRomPoint newPoint){ FreeCamPanel.SetCameraRotation(newPoint.rotation); FreeCamPanel.SetCameraPosition(newPoint.position); - FreeCamPanel.ourCamera.fieldOfView = newPoint.fov; + FreeCamPanel.SetFOV(newPoint.fov); } private CatmullRomPoint GetPointFromPath(float d)