diff --git a/Engine.Core/Abstract/ICamera3D.cs b/Engine.Core/Abstract/ICamera3D.cs
new file mode 100644
index 0000000..01ce185
--- /dev/null
+++ b/Engine.Core/Abstract/ICamera3D.cs
@@ -0,0 +1,26 @@
+namespace Engine.Core;
+
+///
+/// Represents a 3D camera in the engine.
+///
+public interface ICamera3D : IBehaviour3D
+{
+ ///
+ /// Field of View (FOV) value of the camera
+ ///
+ float FieldOfView { get; set; }
+
+ ///
+ /// Converts a position from screen coordinates to a .
+ ///
+ /// The position in screen coordinates.
+ /// The originating from the camera to the screen position in world coordinates.
+ Ray3D ScreenToWorldRay(Vector2D screenPosition);
+
+ ///
+ /// Converts a position from world coordinates to screen coordinates.
+ ///
+ /// The position in world coordinates.
+ /// The position in screen coordinates.
+ Vector2D WorldToScreenPosition(Vector3D worldPosition);
+}
diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera3D.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera3D.cs
new file mode 100644
index 0000000..6a9440f
--- /dev/null
+++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/MonoGameCamera3D.cs
@@ -0,0 +1,131 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+using Engine.Core;
+
+namespace Engine.Integration.MonoGame;
+
+public class MonoGameCamera3D : BehaviourBase, ICamera3D, IFirstFrameUpdate, IPreDraw
+{
+ public Event OnViewChanged { get; } = new();
+ public Event OnProjectionChanged { get; } = new();
+ public Event OnViewportChanged { get; } = new();
+ public Event OnFieldOfViewChanged { get; } = new();
+
+ private Matrix _view = Matrix.Identity;
+ private Matrix _projection = Matrix.Identity;
+ private Viewport _viewport = default;
+ private float _fieldOfView = 1f;
+
+ public GraphicsDeviceManager Graphics { get; private set; } = null!;
+ public ITransform3D Transform { get; private set; } = null!;
+
+ public Matrix View
+ {
+ get => _view;
+ set
+ {
+ if (_view == value)
+ return;
+
+ Matrix previousView = _view;
+ _view = value;
+ OnViewChanged.Invoke(this, new(previousView));
+ }
+ }
+ public Matrix Projection
+ {
+ get => _projection;
+ set
+ {
+ if (_projection == value)
+ return;
+
+ Matrix previousProjection = _projection;
+ _projection = value;
+ OnProjectionChanged.Invoke(this, new(previousProjection));
+ }
+ }
+
+ public Vector3D Position
+ {
+ get => Transform.Position;
+ set => Transform.Position = value;
+ }
+
+ public Viewport Viewport
+ {
+ get => _viewport;
+ set
+ {
+ if (_viewport.Equals(value))
+ return;
+
+ Viewport previousViewport = _viewport;
+ _viewport = value;
+ OnViewportChanged.Invoke(this, new(previousViewport));
+ }
+ }
+
+ public float FieldOfView
+ {
+ get => _fieldOfView;
+ set
+ {
+ float newValue = Math.Max(0.1f, value);
+
+ if (_fieldOfView == newValue)
+ return;
+
+ float previousFieldOfView = _fieldOfView;
+ _fieldOfView = newValue;
+ OnFieldOfViewChanged.Invoke(this, new(previousFieldOfView));
+ }
+ }
+
+ public Engine.Core.Quaternion Rotation
+ {
+ get => Transform.Rotation;
+ set => Transform.Rotation = value;
+ }
+
+ // TODO This causes delay since OnPreDraw calls assuming this is called in in Update
+ public Ray3D ScreenToWorldRay(Vector2D screenPosition)
+ {
+ Vector3 nearPoint = new(screenPosition.X, screenPosition.Y, 0f);
+ Vector3 farPoint = new(screenPosition.X, screenPosition.Y, 1f);
+
+ Vector3 worldNear = Viewport.Unproject(nearPoint, _projection, _view, Matrix.Identity);
+ Vector3 worldFar = Viewport.Unproject(farPoint, _projection, _view, Matrix.Identity);
+
+ Vector3 direction = Vector3.Normalize(worldFar - worldNear);
+ return new(worldNear.ToVector3D(), direction.ToVector3D());
+ }
+
+ public Vector2D WorldToScreenPosition(Vector3D worldPosition) => Viewport.Project(worldPosition.ToVector3(), _projection, _view, Matrix.Identity).ToVector3D();
+
+ public void FirstActiveFrame()
+ {
+ Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour().Window.Graphics;
+ Viewport = Graphics.GraphicsDevice.Viewport;
+ }
+
+ public void PreDraw()
+ {
+ 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);
+ }
+
+ protected sealed override void InitializeInternal() => Transform = BehaviourController.GetRequiredBehaviour();
+ protected sealed override void FinalizeInternal() => Transform = null!;
+
+ 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);
+}