Update Camera setup

This commit is contained in:
miku-666
2024-02-07 12:03:39 +01:00
parent 85e05bf83b
commit 2e13d410a7
4 changed files with 129 additions and 68 deletions

View File

@@ -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();
}
}

View File

@@ -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}";
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}