From 96efbc36d0e4ce2f44f0b6679a7c07d510db8d51 Mon Sep 17 00:00:00 2001 From: originalnicodr Date: Fri, 8 Mar 2024 18:47:00 -0300 Subject: [PATCH] Refactored the follow object feature to let the user choose if they want to follow the object position only or if they also want the camera to follow its rotation. --- README.md | 8 +- src/Cinematic/Cells/CamPathNodeCell.cs | 13 +- src/UI/Panels/CamPaths.cs | 135 ++++++++-- src/UI/Panels/FreeCamPanel.cs | 347 ++++++++++++++++--------- src/UI/Widgets/CatmullRom.cs | 30 +-- 5 files changed, 350 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index c525284..4c0bbba 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,9 @@ The original Unity Explorer had a Freecam feature, but even if it was useful at - Blocked rotation from going further when looking directly up or directly down. ### Follow Object -You can click on the "Follow object" button on the panel and select the object you want to follow on screen or click on the "Follow object" button in the inspector screen for more granularity. Should be useful for creating motion blur, or to use alongside the [camera paths](#camera-paths). +You can click on the "Follow object" button on the panel and select the object you want the camera to follow or click on the "Follow object" button in the inspector screen for more granularity. This can be used as it is, but it's even more useful when playing with [camera paths](#camera-paths), as you can create a path for the camera to walk relative to the object + +By default the camera only follows the object's position, but you can also make it follow its rotation as if the camera was physically bound to the object by checking the "Follow Object Rotation" toggle. Should be useful for mimicking a car camera, a character POV, or creating motion blur. ### Game input block for Unity's legacy system Added game input block for Unity's legacy system. You can now block (or unblock) the game's input when using the freecam, as long as the game is using the Unity Legacy Input system. If the game uses a custom solution or the latest Unity system then this won't work. Implementing this for Unity's new system is in the backlog, so if you find a game using it (should say "Initialized new InputSystem support." on the logs) then please let me know so I can implement it using that game! @@ -322,6 +324,10 @@ Building individual configurations from your IDE is fine, though note that the i * [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used as the base for UnityExplorer's C# console. * [Geoffrey Horsington](https://github.com/ghorsington) for [mcs-unity](https://github.com/sinai-dev/mcs-unity) \[no license\], used as the `Mono.CSharp` reference for the C# Console. +# Crediting + +Even tho it's not necessary, if you happen to use this mod in the marketing campaign of a game and find it useful please consider including it in the credits! + # Support If you have found this project fun or useful in any capacity please consider [supporting me on Ko-fi](https://ko-fi.com/originalnicodr). And please also consider donating to the people in the acknowledgments above! As well as the mod loader maintainers. diff --git a/src/Cinematic/Cells/CamPathNodeCell.cs b/src/Cinematic/Cells/CamPathNodeCell.cs index cf0823f..ee14f46 100644 --- a/src/Cinematic/Cells/CamPathNodeCell.cs +++ b/src/Cinematic/Cells/CamPathNodeCell.cs @@ -33,8 +33,8 @@ namespace UnityExplorer.UI.Panels ButtonRef moveToCameraButton = UIFactory.CreateButton(UIRoot, "Copy Camera pos and rot", "Copy Camera pos and rot"); UIFactory.SetLayoutElement(moveToCameraButton.GameObject, minWidth: 130, minHeight: 25, flexibleWidth: 9999); moveToCameraButton.OnClick += () => { - point.position = GetCamPathsPanel().followObject != null ? FreeCamPanel.ourCamera.transform.localPosition : FreeCamPanel.ourCamera.transform.position; - point.rotation = GetCamPathsPanel().followObject != null ? FreeCamPanel.ourCamera.transform.localRotation : FreeCamPanel.ourCamera.transform.rotation; + point.rotation = FreeCamPanel.GetCameraRotation(); + point.position = FreeCamPanel.GetCameraPosition(); GetCamPathsPanel().controlPoints[index] = point; GetCamPathsPanel().MaybeRedrawPath(); @@ -50,13 +50,8 @@ namespace UnityExplorer.UI.Panels ButtonRef moveToPointButton = UIFactory.CreateButton(UIRoot, "Move Cam to Node", "Move Cam to Node"); UIFactory.SetLayoutElement(moveToPointButton.GameObject, minWidth: 100, minHeight: 25, flexibleWidth: 9999); moveToPointButton.OnClick += () => { - if (GetCamPathsPanel().followObject != null){ - FreeCamPanel.ourCamera.transform.localPosition = point.position; - FreeCamPanel.ourCamera.transform.localRotation = point.rotation; - } else { - FreeCamPanel.ourCamera.transform.position = point.position; - FreeCamPanel.ourCamera.transform.rotation = point.rotation; - } + FreeCamPanel.SetCameraRotation(point.rotation); + FreeCamPanel.SetCameraPosition(point.position); FreeCamPanel.ourCamera.fieldOfView = point.fov; }; diff --git a/src/UI/Panels/CamPaths.cs b/src/UI/Panels/CamPaths.cs index 4c2dda7..2bcd49c 100644 --- a/src/UI/Panels/CamPaths.cs +++ b/src/UI/Panels/CamPaths.cs @@ -22,7 +22,7 @@ namespace UnityExplorer.UI.Panels { controlPoints = new List(); followObject = null; - pathVisualizer = new GameObject("PathVisualizer"); + pathVisualizer = null; time = 10; // Timer setup @@ -69,6 +69,8 @@ namespace UnityExplorer.UI.Panels public int ItemCount => controlPoints.Count; private static bool DoneScrollPoolInit; + CamPointsUpdater camPointsUpdater; + public override void SetActive(bool active) { base.SetActive(active); @@ -248,10 +250,9 @@ namespace UnityExplorer.UI.Panels private void ToggleVisualizePath(bool enable){ // Had to include this check because the pathVisualizer was null for some reason - if (pathVisualizer == null) pathVisualizer = new GameObject("PathVisualizer"); if (enable){ if (controlPoints.Count > 2){ - if (followObject != null) pathVisualizer.transform.SetParent(followObject.transform, true); + CreateAndMovePathVisualizer(); UpdateCatmullRomMoverData(); List lookaheadPoints = GetCameraPathsManager().GetLookaheadPoints(); @@ -265,9 +266,16 @@ namespace UnityExplorer.UI.Panels } Vector3 arrowPos = lookaheadPoints[i].position; - if (followObject != null) arrowPos = followObject.transform.TransformPoint(arrowPos); + if (followObject != null){ + if (!FreeCamPanel.followRotationToggle.isOn){ + arrowPos = Quaternion.Inverse(FreeCamPanel.followObject.transform.rotation) * arrowPos; + } + // TODO: Avoid using TransformPoint + arrowPos = followObject.transform.TransformPoint(arrowPos); + } Quaternion arrowRot = lookaheadPoints[i].rotation; - if (followObject != null) arrowRot = followObject.transform.rotation * arrowRot; + if (followObject != null && FreeCamPanel.followRotationToggle.isOn) arrowRot = followObject.transform.rotation * arrowRot; + // We could expose the color of the arrow to a setting GameObject arrow = ArrowGenerator.CreateArrow(arrowPos, arrowRot, Color.green); arrow.transform.SetParent(pathVisualizer.transform, true); @@ -278,7 +286,8 @@ namespace UnityExplorer.UI.Panels else { if (pathVisualizer) { UnityEngine.Object.Destroy(pathVisualizer); - pathVisualizer = new GameObject("PathVisualizer"); + pathVisualizer = null; + CreateAndMovePathVisualizer(); } } } @@ -353,11 +362,10 @@ namespace UnityExplorer.UI.Panels void AddNode_OnClick(){ EventSystemHelper.SetSelectedGameObject(null); - Camera freeCam = FreeCamPanel.ourCamera; CatmullRom.CatmullRomPoint point = new CatmullRom.CatmullRomPoint( - followObject != null ? freeCam.transform.localPosition : freeCam.transform.position, - followObject != null ? freeCam.transform.localRotation : freeCam.transform.rotation, - freeCam.fieldOfView + FreeCamPanel.GetCameraPosition(), + FreeCamPanel.GetCameraRotation(), + FreeCamPanel.ourCamera.fieldOfView ); controlPoints.Add(point); @@ -387,38 +395,67 @@ namespace UnityExplorer.UI.Panels public void UpdatedFollowObject(GameObject obj){ // Had to include this check because the pathVisualizer was null for some reason - if (pathVisualizer == null) pathVisualizer = new GameObject("PathVisualizer"); if (followObject != null){ - TranslatePointsToGlobal(); - pathVisualizer.transform.SetParent(null, true); + // destroy the obhject from the parent + GameObject.Destroy(camPointsUpdater); + camPointsUpdater = null; } followObject = obj; if (obj != null){ - TranslatePointsToLocal(); - pathVisualizer.transform.SetParent(obj.transform, true); + // create the component on the object itself + camPointsUpdater = RuntimeHelper.AddComponent(obj, typeof(CamPointsUpdater)); + //camPointsUpdater = obj.AddComponent(); + + camPointsUpdater.SetFollowObject(obj); } //nodesScrollPool.Refresh(true, false); } - void TranslatePointsToGlobal() { + public void CreateAndMovePathVisualizer(){ + if (pathVisualizer == null) + pathVisualizer = new GameObject("PathVisualizer"); + + if (followObject != null){ + pathVisualizer.transform.position = followObject.transform.position; + if (FreeCamPanel.followRotationToggle.isOn){ + Vector3 offset = pathVisualizer.transform.position - followObject.transform.position; + pathVisualizer.transform.position = pathVisualizer.transform.position - offset + followObject.transform.rotation * offset; + pathVisualizer.transform.rotation = followObject.transform.rotation; + } + } + } + + public void TranslatePointsPositionToGlobal(){ + List newControlPoints = new List(); + foreach(CatmullRom.CatmullRomPoint point in controlPoints){ + Vector3 newPos = point.position + followObject.transform.position; + + CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, point.rotation, point.fov); + newControlPoints.Add(newPoint); + } + + controlPoints = newControlPoints; + } + + // Also changes position based on rotation + public void TranslatePointsRotationToGlobal(){ List newControlPoints = new List(); foreach(CatmullRom.CatmullRomPoint point in controlPoints){ - Vector3 newPos = followObject.transform.TransformPoint(point.position); Quaternion newRot = followObject.transform.rotation * point.rotation; - CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, newRot, point.fov); + Vector3 newPos = followObject.transform.rotation * point.position; + CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, newRot, point.fov); newControlPoints.Add(newPoint); } controlPoints = newControlPoints; } - void TranslatePointsToLocal() { + public void TranslatePointsPositionToLocal(){ List newControlPoints = new List(); foreach(CatmullRom.CatmullRomPoint point in controlPoints){ - Vector3 newPos = followObject.transform.InverseTransformPoint(point.position); - Quaternion newRot = Quaternion.Inverse(followObject.transform.rotation) * point.rotation; - CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, newRot, point.fov); + Vector3 newPos = point.position - followObject.transform.position; + CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, point.rotation, point.fov); newControlPoints.Add(newPoint); } @@ -426,9 +463,22 @@ namespace UnityExplorer.UI.Panels controlPoints = newControlPoints; } - void UpdateCatmullRomMoverData(){ + // Also changes position based on rotation + public void TranslatePointsRotationToLocal(){ + List newControlPoints = new List(); + foreach(CatmullRom.CatmullRomPoint point in controlPoints){ + Quaternion newRot = Quaternion.Inverse(followObject.transform.rotation) * point.rotation; + Vector3 newPos = Quaternion.Inverse(followObject.transform.rotation) * point.position; + + CatmullRom.CatmullRomPoint newPoint = new CatmullRom.CatmullRomPoint(newPos, newRot, point.fov); + newControlPoints.Add(newPoint); + } + + controlPoints = newControlPoints; + } + + void UpdateCatmullRomMoverData() { GetCameraPathsManager().setClosedLoop(closedLoop); - GetCameraPathsManager().setLocalPoints(followObject != null); GetCameraPathsManager().setSplinePoints(controlPoints.ToArray()); GetCameraPathsManager().setTime(time); GetCameraPathsManager().setCatmullRomVariables(alphaCatmullRomValue, tensionCatmullRomValue); @@ -436,4 +486,41 @@ namespace UnityExplorer.UI.Panels GetCameraPathsManager().CalculateLookahead(); } } + + public class CamPointsUpdater : MonoBehaviour + { + GameObject followObject; + +#if CPP + static CamPointsUpdater() + { + ClassInjector.RegisterTypeInIl2Cpp(); + } + + public CamPointsUpdater(IntPtr ptr) : base(ptr) { } +#endif + + internal void SetFollowObject(GameObject obj){ + followObject = obj; + } + + internal void Update() + { + if (followObject == null) + return; + + //CamPathsPanel.MaybeRedrawPath(); + + CamPaths CamPathsPanel = UIManager.GetPanel(UIManager.Panels.CamPaths); + + if (CamPathsPanel.pathVisualizer){ + CamPathsPanel.pathVisualizer.transform.position = followObject.transform.position; + if (FreeCamPanel.followRotationToggle.isOn){ + Vector3 offset = CamPathsPanel.pathVisualizer.transform.position - FreeCamPanel.followObject.transform.position; + CamPathsPanel.pathVisualizer.transform.position = CamPathsPanel.pathVisualizer.transform.position - offset + FreeCamPanel.followObject.transform.rotation * offset; + CamPathsPanel.pathVisualizer.transform.rotation = followObject.transform.rotation; + } + } + } + } } diff --git a/src/UI/Panels/FreeCamPanel.cs b/src/UI/Panels/FreeCamPanel.cs index 57b43e3..debcc27 100644 --- a/src/UI/Panels/FreeCamPanel.cs +++ b/src/UI/Panels/FreeCamPanel.cs @@ -57,6 +57,7 @@ namespace UnityExplorer.UI.Panels static InputFieldRef moveSpeedInput; static Text followObjectLabel; static ButtonRef inspectButton; + public static Toggle followRotationToggle; static bool disabledCinemachine; public static bool supportedInput => InputManager.CurrentType == InputType.Legacy; @@ -70,6 +71,8 @@ namespace UnityExplorer.UI.Panels static float farClipPlaneValue; public static GameObject followObject = null; + public static Vector3 followObjectLastPosition = Vector3.zero; + public static Quaternion followObjectLastRotation = Quaternion.identity; private static FreecamCursorUnlocker freecamCursorUnlocker = null; @@ -225,7 +228,7 @@ namespace UnityExplorer.UI.Panels } } - static void SetCameraPosition(Vector3 pos) + static void SetCameraPositionInput(Vector3 pos) { if (!ourCamera || lastSetCameraPosition == pos) return; @@ -285,6 +288,22 @@ namespace UnityExplorer.UI.Panels AddSpacer(5); + GameObject togglesRow = UIFactory.CreateHorizontalGroup(ContentRoot, "TogglesRow", false, false, true, true, 3, default, new(1, 1, 1, 0)); + + GameObject blockFreecamMovement = UIFactory.CreateToggle(togglesRow, "blockFreecamMovement", out blockFreecamMovementToggle, out Text blockFreecamMovementText); + UIFactory.SetLayoutElement(blockFreecamMovement, minHeight: 25, flexibleWidth: 9999); + blockFreecamMovementToggle.isOn = false; + blockFreecamMovementText.text = "Block Freecam movement"; + + if (supportedInput){ + GameObject blockGamesInputOnFreecam = UIFactory.CreateToggle(togglesRow, "blockGamesInputOnFreecam", out blockGamesInputOnFreecamToggle, out Text blockGamesInputOnFreecamText); + UIFactory.SetLayoutElement(blockGamesInputOnFreecam, minHeight: 25, flexibleWidth: 9999); + blockGamesInputOnFreecamToggle.isOn = true; + blockGamesInputOnFreecamText.text = "Block games input on Freecam"; + } + + AddSpacer(5); + GameObject nearCameraClipGroup = AddInputField("NearClipPlane", "Near clip plane:", "0", out nearClipPlaneInput, NearClipInput_OnEndEdit); nearClipPlaneInput.Text = nearClipPlaneValue.ToString(); @@ -325,7 +344,6 @@ namespace UnityExplorer.UI.Panels AddSpacer(5); - followObjectLabel = UIFactory.CreateLabel(ContentRoot, "CurrentFollowObject", "Not following any object."); UIFactory.SetLayoutElement(followObjectLabel.gameObject, minWidth: 100, minHeight: 25); @@ -339,24 +357,26 @@ namespace UnityExplorer.UI.Panels UIFactory.SetLayoutElement(releaseFollowButton.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999); releaseFollowButton.OnClick += ReleaseFollowButton_OnClick; + GameObject followRotationGameObject = UIFactory.CreateToggle(ContentRoot, "followRotationToggle", out followRotationToggle, out Text followRotationText); + UIFactory.SetLayoutElement(followRotationGameObject, minHeight: 25, flexibleWidth: 9999); + followRotationToggle.isOn = false; + followRotationText.text = "Follow Object Rotation"; + followRotationToggle.onValueChanged.AddListener((value) => { + if (followObject != null){ + CamPaths CamPathsPanel = UIManager.GetPanel(UIManager.Panels.CamPaths); + if (value){ + CamPathsPanel.TranslatePointsRotationToLocal(); + } + else { + CamPathsPanel.TranslatePointsRotationToGlobal(); + } + + CamPathsPanel.MaybeRedrawPath(); + } + }); + AddSpacer(5); - GameObject togglesRow = UIFactory.CreateHorizontalGroup(ContentRoot, "TogglesRow", false, false, true, true, 3, default, new(1, 1, 1, 0)); - - GameObject blockFreecamMovement = UIFactory.CreateToggle(togglesRow, "blockFreecamMovement", out blockFreecamMovementToggle, out Text blockFreecamMovementText); - UIFactory.SetLayoutElement(blockFreecamMovement, minHeight: 25, flexibleWidth: 9999); - blockFreecamMovementToggle.isOn = false; - blockFreecamMovementText.text = "Block Freecam movement"; - - if (supportedInput){ - GameObject blockGamesInputOnFreecam = UIFactory.CreateToggle(togglesRow, "blockGamesInputOnFreecam", out blockGamesInputOnFreecamToggle, out Text blockGamesInputOnFreecamText); - UIFactory.SetLayoutElement(blockGamesInputOnFreecam, minHeight: 25, flexibleWidth: 9999); - blockGamesInputOnFreecamToggle.isOn = true; - blockGamesInputOnFreecamText.text = "Block games input on Freecam"; - - AddSpacer(5); - } - string instructions = "Controls:\n" + $"- {ConfigManager.Forwards_1.Value},{ConfigManager.Backwards_1.Value},{ConfigManager.Left_1.Value},{ConfigManager.Right_1.Value} / {ConfigManager.Forwards_2.Value},{ConfigManager.Backwards_2.Value},{ConfigManager.Left_2.Value},{ConfigManager.Right_2.Value}: Movement\n" + $"- {ConfigManager.Up.Value}: Move up\n" + @@ -425,10 +445,24 @@ namespace UnityExplorer.UI.Panels } public static void FollowObjectAction(GameObject obj){ - followObject = obj; - followObjectLabel.text = $"Following: {obj.name}"; CamPaths CamPathsPanel = UIManager.GetPanel(UIManager.Panels.CamPaths); + + if (followObject != null){ + if (followRotationToggle.isOn) CamPathsPanel.TranslatePointsRotationToGlobal(); + CamPathsPanel.TranslatePointsPositionToGlobal(); + } + + followObject = obj; + followObjectLastPosition = followObject.transform.position; + followObjectLastRotation = followObject.transform.rotation; + followObjectLabel.text = $"Following: {obj.name}"; + CamPathsPanel.UpdatedFollowObject(obj); + + CamPathsPanel.TranslatePointsPositionToLocal(); + if (followRotationToggle.isOn) CamPathsPanel.TranslatePointsRotationToLocal(); + + CamPathsPanel.MaybeRedrawPath(); } void FollowButton_OnClick() @@ -438,12 +472,17 @@ namespace UnityExplorer.UI.Panels void ReleaseFollowButton_OnClick() { - if (followObject && ourCamera.transform.IsChildOf(followObject.transform)){ - ourCamera.transform.SetParent(null, true); + if (followObject){ followObject = null; + followObjectLastPosition = Vector3.zero; + followObjectLastRotation = Quaternion.identity; followObjectLabel.text = "Not following any object"; } CamPaths CamPathsPanel = UIManager.GetPanel(UIManager.Panels.CamPaths); + + if (followRotationToggle.isOn) CamPathsPanel.TranslatePointsRotationToGlobal(); + CamPathsPanel.TranslatePointsPositionToGlobal(); + CamPathsPanel.UpdatedFollowObject(null); } @@ -463,11 +502,6 @@ namespace UnityExplorer.UI.Panels void OnUseGameCameraToggled(bool value) { - // If the previous camera is following a game object we remove it from tis childs. - if (followObject && ourCamera.transform.IsChildOf(followObject.transform)){ - ourCamera.transform.SetParent(null, true); - } - EventSystemHelper.SetSelectedGameObject(null); if (!inFreeCamMode) @@ -484,8 +518,8 @@ namespace UnityExplorer.UI.Panels if (inFreeCamMode && ourCamera) { - ourCamera.transform.position = (Vector3)currentUserCameraPosition; - ourCamera.transform.rotation = (Quaternion)currentUserCameraRotation; + SetCameraPosition((Vector3)currentUserCameraPosition, true); + SetCameraRotation((Quaternion)currentUserCameraRotation, true); ourCamera.fieldOfView = originalCameraFOV; } @@ -503,7 +537,7 @@ namespace UnityExplorer.UI.Panels return; } - SetCameraPosition(parsed); + SetCameraPositionInput(parsed); } void MoveSpeedInput_OnEndEdit(string input) @@ -557,6 +591,55 @@ namespace UnityExplorer.UI.Panels public static bool ShouldOverrideInput(){ return inFreeCamMode && blockGamesInputOnFreecamToggle.isOn; } + + // Getters and Setters for camera position and rotation + public static Vector3 GetCameraPosition(bool isAbsolute = false){ + if (isAbsolute) return ourCamera.transform.position; + if (followObject){ + if (followRotationToggle.isOn){ + return Quaternion.Inverse(followObject.transform.rotation) * (ourCamera.transform.position - followObject.transform.position); + } + else { + return ourCamera.transform.position - followObject.transform.position; + } + } + return ourCamera.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; + } + + public static void SetCameraPosition(Vector3 newPosition, bool isAbsolute = false){ + if (isAbsolute){ + ourCamera.transform.position = newPosition; + } + else if (followObject){ + if (followRotationToggle.isOn){ + ourCamera.transform.position = followObject.transform.rotation * newPosition + followObject.transform.position; + } + else { + ourCamera.transform.position = newPosition + followObject.transform.position; + } + } + else { + ourCamera.transform.position = newPosition; + } + } + + public static void SetCameraRotation(Quaternion newRotation, bool isAbsolute = false){ + if (isAbsolute){ + ourCamera.transform.rotation = newRotation; + } + else if (followObject && followRotationToggle.isOn){ + ourCamera.transform.rotation = followObjectLastRotation * newRotation; + } + else { + ourCamera.transform.rotation = newRotation; + } + } } internal class FreeCamBehaviour : MonoBehaviour @@ -580,113 +663,125 @@ namespace UnityExplorer.UI.Panels return; } - if (FreeCamPanel.followObject && !FreeCamPanel.ourCamera.transform.IsChildOf(FreeCamPanel.followObject.transform)){ - FreeCamPanel.ourCamera.transform.SetParent(FreeCamPanel.followObject.transform, true); - } - - // ------------- Handle input ---------------- - - if (FreeCamPanel.blockFreecamMovementToggle.isOn || FreeCamPanel.cameraPathMover.playingPath){ - return; - } - Transform transform = FreeCamPanel.ourCamera.transform; - FreeCamPanel.currentUserCameraPosition = transform.position; - FreeCamPanel.currentUserCameraRotation = transform.rotation; - - float moveSpeed = FreeCamPanel.desiredMoveSpeed * 0.01665f; //"0.01665f" (60fps) in place of Time.DeltaTime. DeltaTime causes issues when game is paused. - float speedModifier = 1; - if (IInputManager.GetKey(ConfigManager.Speed_Up_Movement.Value)) - speedModifier = 10f; - - if (IInputManager.GetKey(ConfigManager.Speed_Down_Movement.Value)) - speedModifier = 0.1f; - - moveSpeed *= speedModifier; - - if (IInputManager.GetKey(ConfigManager.Left_1.Value) || IInputManager.GetKey(ConfigManager.Left_2.Value)) - transform.position += transform.right * -1 * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Right_1.Value) || IInputManager.GetKey(ConfigManager.Right_2.Value)) - transform.position += transform.right * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Forwards_1.Value) || IInputManager.GetKey(ConfigManager.Forwards_2.Value)) - transform.position += transform.forward * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Backwards_1.Value) || IInputManager.GetKey(ConfigManager.Backwards_2.Value)) - transform.position += transform.forward * -1 * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Up.Value)) - transform.position += transform.up * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Down.Value)) - transform.position += transform.up * -1 * moveSpeed; - - if (IInputManager.GetKey(ConfigManager.Tilt_Left.Value)) - transform.Rotate(0, 0, moveSpeed, Space.Self); - - if (IInputManager.GetKey(ConfigManager.Tilt_Right.Value)) - transform.Rotate(0, 0, - moveSpeed, Space.Self); - - if (IInputManager.GetKey(ConfigManager.Tilt_Reset.Value)){ - // Extract the forward direction of the original quaternion - Vector3 forwardDirection = transform.rotation * Vector3.forward; - // Reset the tilt by creating a new quaternion with no tilt - Quaternion newRotation = Quaternion.LookRotation(forwardDirection, Vector3.up); - - transform.rotation = newRotation; + if (!FreeCamPanel.blockFreecamMovementToggle.isOn && !FreeCamPanel.cameraPathMover.playingPath){ + ProcessInput(); } - if (IInputManager.GetMouseButton(1)) - { - Vector3 mouseDelta = IInputManager.MousePosition - FreeCamPanel.previousMousePosition; - - float newRotationX = transform.localEulerAngles.y + mouseDelta.x * 0.3f; - float newRotationY = transform.localEulerAngles.x - mouseDelta.y * 0.3f; + if (FreeCamPanel.followObject != null){ + // position update + transform.position += FreeCamPanel.followObject.transform.position - FreeCamPanel.followObjectLastPosition; - // Block the camera rotation to not go further than looking directly up or down. - // We give a little extra to the [0, 90] rotation segment to not get the camera rotation stuck. - // If it doesn't work in some game we should revisit this. - newRotationY = newRotationY > 180f ? Mathf.Clamp(newRotationY, 270f, 360f) : Mathf.Clamp(newRotationY, -1f, 90.0f); + 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; + } - transform.localEulerAngles = new Vector3(newRotationY, newRotationX, transform.localEulerAngles.z); - - // Apply the rotation changes while maintaining the camera's current roll. - // Not using this method as it can easily modify the tilt, which is undesired. - - /*float pitch = -mouseDelta.y * speedModifier * Time.deltaTime; - float yaw = mouseDelta.x * speedModifier * Time.deltaTime; - - Vector3 forwardDirection = transform.rotation * Vector3.forward; - Vector3 rightDirection = transform.rotation * Vector3.right; - Vector3 upDirection = transform.rotation * Vector3.up; - - Quaternion pitchRotation = Quaternion.AngleAxis(pitch, rightDirection); - Quaternion yawRotation = Quaternion.AngleAxis(yaw, upDirection); - - transform.rotation = pitchRotation * yawRotation * transform.rotation;*/ - } - - if (IInputManager.GetKey(ConfigManager.Decrease_FOV.Value)) - { - FreeCamPanel.ourCamera.fieldOfView -= moveSpeed; - } - - if (IInputManager.GetKey(ConfigManager.Increase_FOV.Value)) - { - FreeCamPanel.ourCamera.fieldOfView += moveSpeed; - } - - if (IInputManager.GetKey(ConfigManager.Reset_FOV.Value)){ - FreeCamPanel.ourCamera.fieldOfView = FreeCamPanel.usingGameCamera ? FreeCamPanel.originalCameraFOV : 60; + FreeCamPanel.followObjectLastPosition = FreeCamPanel.followObject.transform.position; + FreeCamPanel.followObjectLastRotation = FreeCamPanel.followObject.transform.rotation; } FreeCamPanel.UpdatePositionInput(); - - FreeCamPanel.previousMousePosition = IInputManager.MousePosition; } } + + internal void ProcessInput(){ + FreeCamPanel.currentUserCameraPosition = transform.position; + FreeCamPanel.currentUserCameraRotation = transform.rotation; + + float moveSpeed = FreeCamPanel.desiredMoveSpeed * 0.01665f; //"0.01665f" (60fps) in place of Time.DeltaTime. DeltaTime causes issues when game is paused. + float speedModifier = 1; + if (IInputManager.GetKey(ConfigManager.Speed_Up_Movement.Value)) + speedModifier = 10f; + + if (IInputManager.GetKey(ConfigManager.Speed_Down_Movement.Value)) + speedModifier = 0.1f; + + moveSpeed *= speedModifier; + + if (IInputManager.GetKey(ConfigManager.Left_1.Value) || IInputManager.GetKey(ConfigManager.Left_2.Value)) + transform.position += transform.right * -1 * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Right_1.Value) || IInputManager.GetKey(ConfigManager.Right_2.Value)) + transform.position += transform.right * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Forwards_1.Value) || IInputManager.GetKey(ConfigManager.Forwards_2.Value)) + transform.position += transform.forward * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Backwards_1.Value) || IInputManager.GetKey(ConfigManager.Backwards_2.Value)) + transform.position += transform.forward * -1 * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Up.Value)) + transform.position += transform.up * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Down.Value)) + transform.position += transform.up * -1 * moveSpeed; + + if (IInputManager.GetKey(ConfigManager.Tilt_Left.Value)) + transform.Rotate(0, 0, moveSpeed, Space.Self); + + if (IInputManager.GetKey(ConfigManager.Tilt_Right.Value)) + transform.Rotate(0, 0, - moveSpeed, Space.Self); + + if (IInputManager.GetKey(ConfigManager.Tilt_Reset.Value)){ + // Extract the forward direction of the original quaternion + Vector3 forwardDirection = transform.rotation * Vector3.forward; + // Reset the tilt by creating a new quaternion with no tilt + Quaternion newRotation = Quaternion.LookRotation(forwardDirection, Vector3.up); + + transform.rotation = newRotation; + } + + if (IInputManager.GetMouseButton(1)) + { + Vector3 mouseDelta = IInputManager.MousePosition - FreeCamPanel.previousMousePosition; + + float newRotationX = transform.localEulerAngles.y + mouseDelta.x * 0.3f; + float newRotationY = transform.localEulerAngles.x - mouseDelta.y * 0.3f; + + // Block the camera rotation to not go further than looking directly up or down. + // We give a little extra to the [0, 90] rotation segment to not get the camera rotation stuck. + // If it doesn't work in some game we should revisit this. + newRotationY = newRotationY > 180f ? Mathf.Clamp(newRotationY, 270f, 360f) : Mathf.Clamp(newRotationY, -1f, 90.0f); + + transform.localEulerAngles = new Vector3(newRotationY, newRotationX, transform.localEulerAngles.z); + + // Apply the rotation changes while maintaining the camera's current roll. + // Not using this method as it can easily modify the tilt, which is undesired. + + /*float pitch = -mouseDelta.y * speedModifier * Time.deltaTime; + float yaw = mouseDelta.x * speedModifier * Time.deltaTime; + + Vector3 forwardDirection = transform.rotation * Vector3.forward; + Vector3 rightDirection = transform.rotation * Vector3.right; + Vector3 upDirection = transform.rotation * Vector3.up; + + Quaternion pitchRotation = Quaternion.AngleAxis(pitch, rightDirection); + Quaternion yawRotation = Quaternion.AngleAxis(yaw, upDirection); + + transform.rotation = pitchRotation * yawRotation * transform.rotation;*/ + } + + if (IInputManager.GetKey(ConfigManager.Decrease_FOV.Value)) + { + FreeCamPanel.ourCamera.fieldOfView -= moveSpeed; + } + + if (IInputManager.GetKey(ConfigManager.Increase_FOV.Value)) + { + FreeCamPanel.ourCamera.fieldOfView += moveSpeed; + } + + if (IInputManager.GetKey(ConfigManager.Reset_FOV.Value)){ + FreeCamPanel.ourCamera.fieldOfView = FreeCamPanel.usingGameCamera ? FreeCamPanel.originalCameraFOV : 60; + } + + FreeCamPanel.previousMousePosition = IInputManager.MousePosition; + } } // 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 8dc4d92..74641d0 100644 --- a/src/UI/Widgets/CatmullRom.cs +++ b/src/UI/Widgets/CatmullRom.cs @@ -109,8 +109,6 @@ namespace UnityExplorer.CatmullRom // Current position in the path, from 0 to 1 float delta; - bool arePointsLocal; - float tension = 0; float alpha = 0.5f; @@ -161,9 +159,6 @@ namespace UnityExplorer.CatmullRom closedLoop = newClosedLoop; } - public void setLocalPoints(bool newArePointsLocal){ - arePointsLocal = newArePointsLocal; - } #if CPP [HideFromIl2Cpp] #endif @@ -185,8 +180,8 @@ namespace UnityExplorer.CatmullRom } private CatmullRomPoint GetCurrentPoint(){ - Vector3 camPos = arePointsLocal ? FreeCamPanel.ourCamera.transform.localPosition : FreeCamPanel.ourCamera.transform.position; - Quaternion camRot = arePointsLocal ? FreeCamPanel.ourCamera.transform.localRotation : FreeCamPanel.ourCamera.transform.rotation; + Vector3 camPos = FreeCamPanel.GetCameraPosition(); + Quaternion camRot = FreeCamPanel.GetCameraRotation(); return new CatmullRomPoint(camPos, camRot, FreeCamPanel.ourCamera.fieldOfView); } @@ -216,7 +211,7 @@ namespace UnityExplorer.CatmullRom // While ends, need another lookaheadDelta for the next Update // It will do, at most, 2 iterations // We check a very small number instead of zero because if not it can get stuck in an infinite loop - while (room <= 0.0001f) { + while (room <= 0.0002f) { // If the camera reached the last lookAhead we stop it if (delta >= 1){ PathFinished(); @@ -241,25 +236,14 @@ namespace UnityExplorer.CatmullRom Vector4 newRot = ra + rb; newRot.Normalize(); - if (arePointsLocal){ - FreeCamPanel.ourCamera.transform.localPosition += direction.position; - FreeCamPanel.ourCamera.transform.localRotation = CatmullRomPoint.Vector4ToQuaternion(newRot); - } else { - FreeCamPanel.ourCamera.transform.position += direction.position; - FreeCamPanel.ourCamera.transform.rotation = CatmullRomPoint.Vector4ToQuaternion(newRot); - } - + FreeCamPanel.SetCameraRotation(CatmullRomPoint.Vector4ToQuaternion(newRot)); + FreeCamPanel.SetCameraPosition(FreeCamPanel.GetCameraPosition() + direction.position); FreeCamPanel.ourCamera.fieldOfView += direction.fov * actual / room; } public void MoveCameraToPoint(CatmullRomPoint newPoint){ - if (arePointsLocal){ - FreeCamPanel.ourCamera.transform.localPosition = newPoint.position; - FreeCamPanel.ourCamera.transform.localRotation = newPoint.rotation; - } else { - FreeCamPanel.ourCamera.transform.position = newPoint.position; - FreeCamPanel.ourCamera.transform.rotation = newPoint.rotation; - } + FreeCamPanel.SetCameraRotation(newPoint.rotation); + FreeCamPanel.SetCameraPosition(newPoint.position); FreeCamPanel.ourCamera.fieldOfView = newPoint.fov; }