feat: added near & far planes to camera3D
This commit is contained in:
@@ -6,7 +6,32 @@ namespace Engine.Core;
|
||||
public interface ICamera3D : IBehaviour3D
|
||||
{
|
||||
/// <summary>
|
||||
/// Field of View (FOV) value of the camera
|
||||
/// Event triggered when the near plane of the <see cref="ICamera3D"/> changes.
|
||||
/// </summary>
|
||||
Event<ICamera3D, NearPlaneChangedArguments> OnNearPlaneChanged { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the far plane of the <see cref="ICamera3D"/> changes.
|
||||
/// </summary>
|
||||
Event<ICamera3D, FarPlaneChangedArguments> OnFarPlaneChanged { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the field of view of the <see cref="ICamera3D"/> changes.
|
||||
/// </summary>
|
||||
Event<ICamera3D, FieldOfViewChangedArguments> OnFieldOfViewChanged { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Near plane distance of the camera.
|
||||
/// </summary>
|
||||
float NearPlane { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Far plane distance of the camera.
|
||||
/// </summary>
|
||||
float FarPlane { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Field of View (FOV) value of the camera in degrees.
|
||||
/// </summary>
|
||||
float FieldOfView { get; set; }
|
||||
|
||||
@@ -23,4 +48,8 @@ public interface ICamera3D : IBehaviour3D
|
||||
/// <param name="worldPosition">The position in world coordinates.</param>
|
||||
/// <returns>The position in screen coordinates.</returns>
|
||||
Vector2D WorldToScreenPosition(Vector3D worldPosition);
|
||||
|
||||
readonly record struct NearPlaneChangedArguments(float PreviousNearPlane);
|
||||
readonly record struct FarPlaneChangedArguments(float PreviousFarPlane);
|
||||
readonly record struct FieldOfViewChangedArguments(float PreviousFieldOfView);
|
||||
}
|
||||
|
@@ -5,17 +5,23 @@ using Engine.Core;
|
||||
|
||||
namespace Engine.Integration.MonoGame;
|
||||
|
||||
public class MonoGameCamera3D : Behaviour, ICamera3D, IFirstFrameUpdate, IPreDraw
|
||||
public class MonoGameCamera3D : Behaviour, ICamera3D, IFirstFrameUpdate, ILastFrameUpdate, IPreDraw
|
||||
{
|
||||
public Event<MonoGameCamera3D, ViewChangedArguments> OnViewChanged { get; } = new();
|
||||
public Event<MonoGameCamera3D, ProjectionChangedArguments> OnProjectionChanged { get; } = new();
|
||||
public Event<MonoGameCamera3D, ViewportChangedArguments> OnViewportChanged { get; } = new();
|
||||
public Event<MonoGameCamera3D, FieldOfViewChangedArguments> OnFieldOfViewChanged { get; } = new();
|
||||
|
||||
public Event<ICamera3D, ICamera3D.NearPlaneChangedArguments> OnNearPlaneChanged { get; } = new();
|
||||
public Event<ICamera3D, ICamera3D.FarPlaneChangedArguments> OnFarPlaneChanged { get; } = new();
|
||||
public Event<ICamera3D, ICamera3D.FieldOfViewChangedArguments> OnFieldOfViewChanged { get; } = new();
|
||||
|
||||
private Matrix _view = Matrix.Identity;
|
||||
private Matrix _projection = Matrix.Identity;
|
||||
private Viewport _viewport = default;
|
||||
private float _fieldOfView = 1f;
|
||||
private float _nearPlane = 0.01f;
|
||||
private float _farPlane = 100f;
|
||||
private float _fieldOfView = Math.DegreeToRadian * 70f;
|
||||
private bool isRecalculationNeeded = true;
|
||||
|
||||
public GraphicsDeviceManager Graphics { get; private set; } = null!;
|
||||
public ITransform3D Transform { get; private set; } = null!;
|
||||
@@ -63,27 +69,53 @@ public class MonoGameCamera3D : Behaviour, ICamera3D, IFirstFrameUpdate, IPreDra
|
||||
|
||||
Viewport previousViewport = _viewport;
|
||||
_viewport = value;
|
||||
SetForRecalculation();
|
||||
OnViewportChanged.Invoke(this, new(previousViewport));
|
||||
}
|
||||
}
|
||||
|
||||
public float NearPlane
|
||||
{
|
||||
get => _nearPlane;
|
||||
set
|
||||
{
|
||||
float previousNearPlane = _nearPlane;
|
||||
_nearPlane = value.Max(0.0001f);
|
||||
SetForRecalculation();
|
||||
OnNearPlaneChanged.Invoke(this, new(previousNearPlane));
|
||||
}
|
||||
}
|
||||
|
||||
public float FarPlane
|
||||
{
|
||||
get => _farPlane;
|
||||
set
|
||||
{
|
||||
float previousFarPlane = _farPlane;
|
||||
_farPlane = value.Max(NearPlane);
|
||||
SetForRecalculation();
|
||||
OnFarPlaneChanged.Invoke(this, new(previousFarPlane));
|
||||
}
|
||||
}
|
||||
|
||||
public float FieldOfView
|
||||
{
|
||||
get => _fieldOfView;
|
||||
get => _fieldOfView * Math.RadianToDegree;
|
||||
set
|
||||
{
|
||||
float newValue = Math.Max(0.1f, value);
|
||||
value = value.Max(0.1f) * Math.DegreeToRadian;
|
||||
|
||||
if (_fieldOfView == newValue)
|
||||
if (_fieldOfView == value)
|
||||
return;
|
||||
|
||||
float previousFieldOfView = _fieldOfView;
|
||||
_fieldOfView = newValue;
|
||||
_fieldOfView = value;
|
||||
SetForRecalculation();
|
||||
OnFieldOfViewChanged.Invoke(this, new(previousFieldOfView));
|
||||
}
|
||||
}
|
||||
|
||||
public Engine.Core.Quaternion Rotation
|
||||
public Core.Quaternion Rotation
|
||||
{
|
||||
get => Transform.Rotation;
|
||||
set => Transform.Rotation = value;
|
||||
@@ -104,28 +136,36 @@ public class MonoGameCamera3D : Behaviour, ICamera3D, IFirstFrameUpdate, IPreDra
|
||||
|
||||
public Vector2D WorldToScreenPosition(Vector3D worldPosition) => Viewport.Project(worldPosition.ToVector3(), _projection, _view, Matrix.Identity).ToVector3D();
|
||||
|
||||
public void LastActiveFrame() => Transform.OnTransformUpdated.RemoveListener(SetDirtyOnTransformUpdate);
|
||||
public void FirstActiveFrame()
|
||||
{
|
||||
Transform = BehaviourController.GetRequiredBehaviour<ITransform3D>();
|
||||
Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour<MonoGameWindowContainer>().Window.Graphics;
|
||||
Viewport = Graphics.GraphicsDevice.Viewport;
|
||||
|
||||
Transform.OnTransformUpdated.AddListener(SetDirtyOnTransformUpdate);
|
||||
}
|
||||
|
||||
private void SetDirtyOnTransformUpdate(ITransform3D sender) => SetForRecalculation();
|
||||
private void SetForRecalculation() => isRecalculationNeeded = true;
|
||||
|
||||
public void PreDraw()
|
||||
{
|
||||
if (!isRecalculationNeeded)
|
||||
return;
|
||||
|
||||
Vector3 cameraPosition = Position.ToVector3();
|
||||
View = Matrix.CreateLookAt(
|
||||
cameraPosition,
|
||||
Transform.Forward.ToVector3() + cameraPosition,
|
||||
Transform.Up.ToVector3()
|
||||
);
|
||||
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Viewport.AspectRatio, 0.1f, 100f);
|
||||
}
|
||||
Projection = Matrix.CreatePerspectiveFieldOfView(_fieldOfView, Viewport.AspectRatio, 0.1f, 100f);
|
||||
|
||||
protected sealed override void InitializeInternal() => Transform = BehaviourController.GetRequiredBehaviour<ITransform3D>();
|
||||
protected sealed override void FinalizeInternal() => Transform = null!;
|
||||
isRecalculationNeeded = false;
|
||||
}
|
||||
|
||||
public readonly record struct ViewChangedArguments(Matrix PreviousView);
|
||||
public readonly record struct ProjectionChangedArguments(Matrix PreviousProjection);
|
||||
public readonly record struct ViewportChangedArguments(Viewport PreviousViewport);
|
||||
public readonly record struct FieldOfViewChangedArguments(float PreviousFieldOfView);
|
||||
}
|
||||
|
Reference in New Issue
Block a user