diff --git a/PCK-Studio/Rendering/Camera/Camera.cs b/PCK-Studio/Rendering/Camera/Camera.cs index 5283847d..12b6199a 100644 --- a/PCK-Studio/Rendering/Camera/Camera.cs +++ b/PCK-Studio/Rendering/Camera/Camera.cs @@ -10,17 +10,8 @@ namespace PckStudio.Rendering.Camera { internal abstract class Camera { - public abstract float Distance { get; set; } - - public abstract Vector2 Position { get; set; } - - internal abstract Matrix4 GetViewProjection(); - - internal abstract void Update(float aspect); - - public override string ToString() - { - return $"Position: {Position}\nDistance: {Distance}"; - } + protected Matrix4 projectionMatrix; + + public abstract Matrix4 GetViewProjection(); } } diff --git a/PCK-Studio/Rendering/Camera/PerspectiveCamera.cs b/PCK-Studio/Rendering/Camera/PerspectiveCamera.cs index 1f905624..11e4deb1 100644 --- a/PCK-Studio/Rendering/Camera/PerspectiveCamera.cs +++ b/PCK-Studio/Rendering/Camera/PerspectiveCamera.cs @@ -1,27 +1,39 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; +using Octokit; using OpenTK; namespace PckStudio.Rendering.Camera { internal class PerspectiveCamera : Camera { - public override float Distance + public float Distance { - get => _position.Z; - set => _position.Z = value; + get => _distance; + set + { + _distance = value; + UpdateViewMatrix(); + } } - public override Vector2 Position - { - get => _position.Xy; - set => _position.Xy = value; - } + public Size ViewportSize { get; set; } public Vector3 WorldPosition => _position; + public Vector3 FocalPoint + { + get => _focalPoint; + set + { + _focalPoint = value; + UpdateViewMatrix(); + } + } public Vector2 Rotation { @@ -30,67 +42,131 @@ namespace PckStudio.Rendering.Camera { _rotation.X = MathHelper.Clamp(value.X, -180f, 180f); _rotation.Y = MathHelper.Clamp(value.Y, -180f, 180f); + UpdateViewMatrix(); } } public Vector3 Orientation => -Vector3.UnitZ; public Vector3 Up = Vector3.UnitY; + public float MinimumFov { get; set; } = 30f; public float MaximumFov { get; set; } = 120f; + public float Fov { get => fov; set => fov = MathHelper.Clamp(value, MinimumFov, MaximumFov); } - public PerspectiveCamera(Vector3 position, Vector2 rotation, float fov) : this(position.Xy, position.Z, rotation, fov) - { } - - public PerspectiveCamera(Vector2 position, float distance, Vector2 rotation, float fov) + public PerspectiveCamera(float fov, Vector3 position) { - LookAt(position); - Distance = distance; Fov = fov; + _position = position; + _focalPoint = Vector3.Zero; } - private Matrix4 viewProjection; private Matrix4 viewMatrix; private float fov; + private float _distance; private Vector3 _position; private Vector2 _rotation; + private Vector3 _focalPoint; - - internal override Matrix4 GetViewProjection() + public override Matrix4 GetViewProjection() { - return viewProjection; + return viewMatrix * projectionMatrix; } - private void UpdateView() + private void UpdateViewMatrix() { + // m_Yaw = m_Pitch = 0.0f; // Lock the camera's rotation + _position = CalculatePosition(); - Matrix4 rotation = Matrix4.CreateFromAxisAngle(new Vector3(-1f, 0f, 0f), MathHelper.DegreesToRadians(Rotation.X)) - * Matrix4.CreateFromAxisAngle(new Vector3(0f, 1f, 0f), MathHelper.DegreesToRadians(Rotation.Y)); + Quaternion orientation = GetOrientation(); + var rotation = Matrix4.CreateTranslation(_position); + rotation *= Matrix4.CreateFromQuaternion(orientation); + rotation *= Matrix4.CreateTranslation(_position).Inverted(); - viewMatrix = Matrix4.LookAt(_position, _position + Orientation, Up) * rotation; + viewMatrix = Matrix4.CreateTranslation(_position) * rotation; + viewMatrix = viewMatrix.Inverted(); } - internal override void Update(float aspect) + public void Update(float aspect) { - UpdateView(); - var projection = Matrix4.CreatePerspectiveFieldOfView((float)MathHelper.DegreesToRadians(Fov), aspect, 1f, 1000f); - viewProjection = viewMatrix * projection; + UpdateViewMatrix(); + projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)MathHelper.DegreesToRadians(Fov), aspect, 1f, 1000f); } - internal void LookAt(Vector2 pos) + private Vector2 GetPanSpeed() { - Position = pos; + float x = Math.Min(ViewportSize.Width / 100.0f, 1.4f); // max = 2.4f + float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f; + + float y = Math.Min(ViewportSize.Height / 100.0f, 1.4f); // max = 2.4f + float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f; + + return new Vector2(xFactor, yFactor); } + public void Pan(Vector2 delta) + { + Pan(delta.X, delta.Y); + } + + public void Pan(float deltaX, float deltaY) + { + Vector2 panSpeed = GetPanSpeed(); + _focalPoint += -GetRightDirection() * deltaX * panSpeed.X * _distance; + _focalPoint += GetUpDirection() * deltaY * panSpeed.Y * _distance; + UpdateViewMatrix(); + } + + public void Rotate(Vector2 delta) + { + Rotate(delta.X, delta.Y); + } + + public void Rotate(float deltaX,float deltaY) + { + const float RotationSpeed = 0.8f; + float yawSign = GetUpDirection().Y < 0 ? -1.0f : 1.0f; + _rotation.Y += yawSign * deltaX * RotationSpeed; + _rotation.X += deltaY * RotationSpeed; + + UpdateViewMatrix(); + } + + public Vector3 GetUpDirection() + { + return GetOrientation() * Up; + } + + public Vector3 GetRightDirection() + { + return GetOrientation() * Vector3.UnitX; + } + + public Vector3 GetForwardDirection() + { + return GetOrientation() * Orientation; + } + + private Vector3 CalculatePosition() + { + Vector3 forwadDirection = GetForwardDirection(); + return FocalPoint - forwadDirection * Distance; + } + + private Quaternion GetOrientation() + { + return new Quaternion(new Vector3(-Rotation)); + } + public override string ToString() { - return $"FOV: {Fov}\nPosition: {Position}\nRotation: {Rotation}"; + return $"FOV: {Fov}\nPosition: {WorldPosition}\nRotation: {Rotation}"; } } diff --git a/PCK-Studio/Rendering/Renderer3D.cs b/PCK-Studio/Rendering/Renderer3D.cs index 479b959b..3b8bb796 100644 --- a/PCK-Studio/Rendering/Renderer3D.cs +++ b/PCK-Studio/Rendering/Renderer3D.cs @@ -60,7 +60,6 @@ namespace PckStudio.Rendering timer.Tick += TimerTick; timer.Start(); VSync = true; - Camera = new PerspectiveCamera(Vector3.UnitZ, Vector2.Zero, 30f); } private void TimerTick(object sender, EventArgs e) @@ -68,6 +67,13 @@ namespace PckStudio.Rendering OnTimerTick?.Invoke(sender, e); Invalidate(); } + + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + Camera.Update(AspectRatio); + Camera.ViewportSize = Size; + } } } diff --git a/PCK-Studio/Rendering/SkinRenderer.cs b/PCK-Studio/Rendering/SkinRenderer.cs index fa8a8769..7ee43723 100644 --- a/PCK-Studio/Rendering/SkinRenderer.cs +++ b/PCK-Studio/Rendering/SkinRenderer.cs @@ -262,10 +262,11 @@ namespace PckStudio.Rendering private const float DefaultCameraDistance = 64f; private void InitializeCamera() { - Camera = new PerspectiveCamera(new Vector2(0f, 5f), DefaultCameraDistance, Vector2.Zero, 60f) + Camera = new PerspectiveCamera(60f, new Vector3(0f, 0f, 0f)) { MinimumFov = 30f, MaximumFov = 120f, + Distance = DefaultCameraDistance, }; } @@ -473,7 +474,6 @@ namespace PckStudio.Rendering return true; case Keys.R: GlobalModelRotation = Vector2.Zero; - CameraTarget = Vector2.Zero; Camera.Distance = DefaultCameraDistance; return true; case Keys.A: @@ -676,21 +676,21 @@ namespace PckStudio.Rendering { base.OnMouseMove(e); // Rotate the model - if (_isLeftMouseDown) + if (e.Button == MouseButtons.Left) { - float rotationYDelta = (float)Math.Round((Cursor.Position.X - CurrentMouseLocation.X) * 0.5f); - float rotationXDelta = (float)Math.Round(-(Cursor.Position.Y - CurrentMouseLocation.Y) * 0.5f); - GlobalModelRotation += new Vector2(rotationXDelta, rotationYDelta); + float deltaX = (Cursor.Position.X - CurrentMouseLocation.X) * 0.5f; + float deltaY = (Cursor.Position.Y - CurrentMouseLocation.Y) * 0.5f; + GlobalModelRotation += new Vector2(-deltaY, deltaX) * Camera.Distance * 0.015f; Cursor.Position = new Point((int)Math.Round(Screen.PrimaryScreen.Bounds.Width / 2d), (int)Math.Round(Screen.PrimaryScreen.Bounds.Height / 2d)); CurrentMouseLocation = Cursor.Position; return; } // Move the model - if (_isRightMouseDown) + if (e.Button == MouseButtons.Right) { - float deltaX = -(Cursor.Position.X - CurrentMouseLocation.X) * 0.05f / (float)MathHelper.DegreesToRadians(Camera.Fov); - float deltaY = (Cursor.Position.Y - CurrentMouseLocation.Y) * 0.05f / (float)MathHelper.DegreesToRadians(Camera.Fov); - CameraTarget += new Vector2(deltaX, deltaY); + float deltaX = (Cursor.Position.X - CurrentMouseLocation.X) * 0.05f; + float deltaY = (Cursor.Position.Y - CurrentMouseLocation.Y) * 0.05f; + Camera.Pan(deltaX, deltaY); Cursor.Position = new Point((int)Math.Round(Screen.PrimaryScreen.Bounds.Width / 2d), (int)Math.Round(Screen.PrimaryScreen.Bounds.Height / 2d)); CurrentMouseLocation = Cursor.Position; } @@ -704,26 +704,14 @@ namespace PckStudio.Rendering protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); - if (!_isLeftMouseDown && e.Button == MouseButtons.Left) + if (e.Button == MouseButtons.Right || e.Button == MouseButtons.Left) { - // If the ray didn't hit the model then rotate the model - PreviousMouseLocation = Cursor.Position; // Store the old mouse position to reset it when the action is over - if (!IsMouseHidden) // Hide the mouse + if (!IsMouseHidden) { IsMouseHidden = true; } - CurrentMouseLocation = Cursor.Position; // Store the current mouse position to use it for the rotate action - _isLeftMouseDown = true; - } - else if (!_isRightMouseDown && e.Button == MouseButtons.Right) - { - PreviousMouseLocation = Cursor.Position; // Store the old mouse position to reset it when the action is over - if (!IsMouseHidden) // Hide the mouse - { - IsMouseHidden = true; - } - CurrentMouseLocation = Cursor.Position; // Store the current mouse position to use it for the move action - _isRightMouseDown = true; + PreviousMouseLocation = Cursor.Position; + CurrentMouseLocation = Cursor.Position; } }