Skip to content

Instantly share code, notes, and snippets.

@VictorHHT
Last active March 5, 2023 13:18
Show Gist options
  • Save VictorHHT/32fc5a9fa5a225a07314eaaca4a25204 to your computer and use it in GitHub Desktop.
Save VictorHHT/32fc5a9fa5a225a07314eaaca4a25204 to your computer and use it in GitHub Desktop.
A tool designed to view models by manipulating the camera instead of the model itself, effectively view the model in every possible angle without the quirkiness in rotating the model. Having additional features like changing view distance, panning via either mouse or keyboard. Smooth has been added to all features for this tool to improve user e…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class VTCameraRotator : MonoBehaviour
{
public enum PanMethods { Mouse, Keyboard };
// The target of the camera rotate sphere
public Camera sceneCamera;
// Target of the camera
public Transform target;
public PanMethods panMethod;
public bool m_CanRotate = true;
[Range(5f, 15f)]
[Tooltip("How sensitive the mouse drag to camera rotation")]
public float mouseRotateSpeed = 5f;
[Range(0.1f, 0.5f)]
public float mousePanSpeed = 0.25f;
[Range(10f, 50f)]
public float keyboardPanSpeed = 20f;
[Range(1f, 5f)]
public float distanceChangeSpeed = 1f;
[Range(0.1f, 0.5f)]
public float rotateSmoothValue = 0.3f;
[Range(0.1f, 0.3f)]
public float distanceChangeSmoothValue = 0.12f;
[Range(0.1f, 0.3f)]
public float panSmoothValue = 0.12f;
public KeyCode leftPanKeyCode = KeyCode.A;
public KeyCode rightPanKeyCode = KeyCode.D;
public KeyCode upPanKeyCode = KeyCode.W;
public KeyCode downPanKeyCode = KeyCode.S;
// Clamp Value
private readonly float m_MinXRotAngle = -85; //min angle around x axis
private readonly float m_MaxXRotAngle = 85; // max angle around x axis
// Mouse rotation related
private float m_RotAroundX;
private float m_RotAroundY;
// Mouse Scroll
private float m_TargetCameraDistance;
private float m_CurrentCameraDistance;
private float m_DefaultCameraDistance;
private float m_DummyDampFloatVelocity = 0;
private float m_MinCameraDistance = 1.5f;
private float m_MaxCameraDistance = 15;
private Vector3 m_DistanceVec;
private Vector3 m_MousePosBeforePanning;
private Vector3 m_RightBeforePannining;
private Vector3 m_UpBeforePanning;
private Vector3 m_CurrentPanDelta;
private Vector3 m_TargetPanDelta;
private Vector3 m_DummyDampVector3Velocity;
private Quaternion m_CurrentRot;
private Quaternion m_TargetRot;
void Awake()
{
if (sceneCamera == null)
{
sceneCamera = Camera.main;
}
}
// Start is called before the first frame update
void Start()
{
m_DefaultCameraDistance = Vector3.Distance(sceneCamera.transform.position, target.position);
m_TargetCameraDistance = m_DefaultCameraDistance;
m_CurrentCameraDistance = m_DefaultCameraDistance;
// negative because default camera z value is negative
m_DistanceVec = new Vector3(0, 0, -m_TargetCameraDistance);
// Initialize camera position
sceneCamera.transform.position = target.position + m_DistanceVec;
// Initial view angle
m_RotAroundX = 40;
m_RotAroundY = 40;
}
// Update is called once per frame
void Update()
{
if (!m_CanRotate)
{
return;
}
m_DistanceVec = new Vector3(0, 0, -m_CurrentCameraDistance);
EditorCameraInput();
HandlePanning();
}
private void LateUpdate()
{
RotateCamera();
SetCameraDistance();
}
public void ResetView()
{
m_RotAroundX = 40;
m_RotAroundY = 40;
ResetPan();
ResetDistance();
}
public void ResetPan()
{
m_TargetPanDelta = Vector3.zero;
}
public void ResetDistance()
{
m_TargetCameraDistance = m_DefaultCameraDistance;
}
public void FrontView()
{
m_RotAroundX = 0;
m_RotAroundY = 0;
ResetPan();
}
//May be the problem with Euler angles
public void TopView()
{
m_RotAroundX = 85;
m_RotAroundY = 0;
ResetPan();
}
public void LeftView()
{
m_RotAroundY = 85;
m_RotAroundX = 0;
ResetPan();
}
private void EditorCameraInput()
{
// Camera Rotation
if (Input.GetMouseButton(0))
{
m_RotAroundX += Input.GetAxis("Mouse Y") * mouseRotateSpeed * -1; // around X
m_RotAroundY += Input.GetAxis("Mouse X") * mouseRotateSpeed;
// Clamp rotX
if (m_RotAroundX < m_MinXRotAngle)
{
m_RotAroundX = m_MinXRotAngle;
}
else if (m_RotAroundX > m_MaxXRotAngle)
{
m_RotAroundX = m_MaxXRotAngle;
}
}
if (panMethod == PanMethods.Mouse)
{
if (Input.GetMouseButtonDown(2))
{
m_RightBeforePannining = transform.right;
m_UpBeforePanning = transform.up;
m_MousePosBeforePanning = Input.mousePosition;
}
if (Input.GetMouseButton(2))
{
Vector2 mouseDelta = Input.mousePosition - m_MousePosBeforePanning;
m_TargetPanDelta += m_RightBeforePannining * mouseDelta.x * mousePanSpeed * Time.deltaTime;
m_TargetPanDelta += m_UpBeforePanning * mouseDelta.y * mousePanSpeed * Time.deltaTime;
}
if (Input.GetMouseButtonUp(2))
{
m_MousePosBeforePanning = Vector2.zero;
}
}
else
{
if (Input.GetKeyDown(leftPanKeyCode) || Input.GetKeyDown(rightPanKeyCode))
{
m_RightBeforePannining = transform.right;
}
if (Input.GetKeyDown(upPanKeyCode) || Input.GetKeyDown(downPanKeyCode))
{
m_UpBeforePanning = transform.up;
}
if (!(Input.GetKey(leftPanKeyCode) && Input.GetKey(rightPanKeyCode)))
{
if (Input.GetKey(leftPanKeyCode))
{
m_TargetPanDelta -= m_RightBeforePannining * keyboardPanSpeed * Time.deltaTime;
}
if (Input.GetKey(rightPanKeyCode))
{
m_TargetPanDelta += m_RightBeforePannining * keyboardPanSpeed * Time.deltaTime;
}
}
if (!(Input.GetKey(downPanKeyCode) && Input.GetKey(upPanKeyCode)))
{
if (Input.GetKey(downPanKeyCode))
{
m_TargetPanDelta -= m_UpBeforePanning * keyboardPanSpeed * Time.deltaTime;
}
if (Input.GetKey(upPanKeyCode))
{
m_TargetPanDelta += m_UpBeforePanning * keyboardPanSpeed * Time.deltaTime;
}
}
}
if (Input.mouseScrollDelta.magnitude > 0)
{
m_TargetCameraDistance += Input.mouseScrollDelta.y * distanceChangeSpeed * -1;
}
}
private void RotateCamera()
{
Vector3 targetRot = new Vector3(m_RotAroundX, m_RotAroundY, 0);
m_TargetRot = Quaternion.Euler(targetRot);
//Rotate Camera
m_CurrentRot = Quaternion.Slerp(m_CurrentRot, m_TargetRot, Time.smoothDeltaTime * rotateSmoothValue * 50);
sceneCamera.transform.position = target.position + m_CurrentRot * m_DistanceVec;
sceneCamera.transform.LookAt(target.position);
sceneCamera.transform.position += m_CurrentPanDelta;
}
void SetCameraDistance()
{
if (m_TargetCameraDistance >= m_MaxCameraDistance)
{
m_TargetCameraDistance = m_MaxCameraDistance;
}
else if (m_TargetCameraDistance <= m_MinCameraDistance)
{
m_TargetCameraDistance = m_MinCameraDistance;
}
m_CurrentCameraDistance = Mathf.SmoothDamp(m_CurrentCameraDistance, m_TargetCameraDistance, ref m_DummyDampFloatVelocity, distanceChangeSmoothValue);
}
void HandlePanning()
{
m_CurrentPanDelta = Vector3.SmoothDamp(m_CurrentPanDelta, m_TargetPanDelta, ref m_DummyDampVector3Velocity, panSmoothValue);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment