I am rotating a globe like XCOM's hologlobe,
I rotate it using Quaternion.RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta).
I found a good value for maxDegreesDelta
, in my case it is 5.0f
.
There is a limit on how close or far the camera can be, let's assume clos is 1.0f
and far is 2.0f
.
I want to be able to zoom into the globe, but obviously when I do, it rotates a bit too fast then.
When zoomed out, rotation speed is satisfying:
When zoomed in, rotation is too fast, making it more difficult to manipulate:
And the problem is even more evident as game view size gets bigger, i.e. fullscreen.
Using Mathf.Lerp
and Mathf.InverseLerp
, I've tried to make maxDegreesDelta
and mouse delta proportional to the distance the camera is but it's hardly convincing.
Note: I rotate the globe, not the camera.
Question:
How can I ensure object rotates at same speed on screen, no matter how close or far camera is ?
Code:
(assumes there is a sphere of radius 0.5
at Vector3.zero
and camera is positioned at Vector3.back
)
using UnityEngine;
using UnityEngine.InputSystem;
namespace Test2
{
public class GeoScapeController : MonoBehaviour
{
#region Public
public Transform TargetObject;
public Camera TargetCamera;
[Range(0.01f, 1.0f)]
public float Sensitivity;
public bool Smooth;
public float ZoomDistanceMin;
public float ZoomDistanceMax;
#endregion
#region Private
[SerializeField]
[HideInInspector]
private Quaternion TargetRotation;
[SerializeField]
[HideInInspector]
private int ZoomLevel;
[SerializeField]
[HideInInspector]
private int ZoomLevels;
[SerializeField]
[HideInInspector]
private Vector3 ZoomVector;
[SerializeField]
[HideInInspector]
private Vector3 ZoomVelocity;
private void Reset()
{
Sensitivity = 0.05f;
Smooth = true;
ZoomDistanceMin = 0.625F;
ZoomDistanceMax = 1.25F;
ZoomLevels = 10;
}
private void Start()
{
TargetRotation = Quaternion.LookRotation(TargetObject.forward, TargetObject.up);
ZoomVector = TargetCamera.transform.position;
}
private void Update()
{
var mouse = Mouse.current;
var delta = mouse.delta.ReadValue();
var scale = new Vector4(-1.0f, +1.0f, +1.0f);
var x = mouse.leftButton.isPressed ? delta.y * scale.y * Sensitivity : 0.0f;
var y = mouse.leftButton.isPressed ? delta.x * scale.x * Sensitivity : 0.0f;
var z = mouse.middleButton.isPressed ? delta.x * scale.z * Sensitivity : 0.0f;
var r = Quaternion.AngleAxis(x, Vector3.right) *
Quaternion.AngleAxis(y, Vector3.up) *
Quaternion.AngleAxis(z, Vector3.forward);
if (Smooth) // hopefully, quaternion limits won't be crossed !
{
TargetRotation = Quaternion.RotateTowards(TargetRotation, r * TargetRotation, 2.5f);
TargetObject.rotation = Quaternion.Slerp(TargetObject.rotation, TargetRotation, Time.deltaTime * 5.0f);
}
else
{
TargetObject.rotation = TargetRotation = r * TargetRotation;
}
var wheel = (int) mouse.scroll.ReadValue().y / 120;
if (wheel != 0)
{
ZoomLevel = Mathf.Clamp(ZoomLevel + wheel, 0, ZoomLevels);
var lerp1 = Mathf.InverseLerp(ZoomLevels, 0, ZoomLevel);
var lerp2 = Mathf.Lerp(ZoomDistanceMin, ZoomDistanceMax, lerp1);
ZoomVector = Vector3.back * lerp2;
}
TargetCamera.transform.position = Smooth
? Vector3.SmoothDamp(TargetCamera.transform.position, ZoomVector, ref ZoomVelocity, 0.3f)
: ZoomVector;
}
#endregion
}
}