BREAKING CHANGE: 4x4 matrices are now column major

This commit is contained in:
2026-01-27 23:45:50 +03:00
parent 9294df8a19
commit 08f32f96e4
3 changed files with 54 additions and 52 deletions

View File

@@ -6,7 +6,7 @@ namespace Engine.Core;
// TODO Comments // TODO Comments
/// <summary> /// <summary>
/// Represents a 4D left handed space matrix. /// Represents a 4D left handed space matrix in a Column Major convention.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Initializes a new instance of the <see cref="Matrix4x4"/> struct with the specified values. /// Initializes a new instance of the <see cref="Matrix4x4"/> struct with the specified values.
@@ -220,10 +220,10 @@ public readonly struct Matrix4x4(
); );
public static Matrix4x4 CreateTranslation(Vector3D position) => new( public static Matrix4x4 CreateTranslation(Vector3D position) => new(
1f, 0f, 0f, 0f, 1f, 0f, 0f, position.X,
0f, 1f, 0f, 0f, 0f, 1f, 0f, position.Y,
0f, 0f, 1f, 0f, 0f, 0f, 1f, position.Z,
position.X, position.Y, position.Z, 1 0f, 0f, 0f, 1f
); );
public static Matrix4x4 CreateScale(float scale) => new( public static Matrix4x4 CreateScale(float scale) => new(
@@ -245,10 +245,10 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f,
0f, c, s, 0f, 0f, c, -s, 0f,
0f, -s, c, 0f, 0f, s, c, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
} }
@@ -258,10 +258,10 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
c, 0f, -s, 0f, c, 0f, s, 0f,
0f, 1f, 0f, 0f, 0f, 1f, 0f, 0f,
s, 0f, c, 0f, -s, 0f, c, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
} }
@@ -271,9 +271,9 @@ public readonly struct Matrix4x4(
float c = Math.Cos(radians); float c = Math.Cos(radians);
float s = Math.Sin(radians); float s = Math.Sin(radians);
return new Matrix4x4( return new(
c, s, 0f, 0f, c, -s, 0f, 0f,
-s, c, 0f, 0f, s, c, 0f, 0f,
0f, 0f, 1f, 0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f 0f, 0f, 0f, 1f
); );
@@ -292,7 +292,7 @@ public readonly struct Matrix4x4(
Vector3D x = up.Cross(z).Normalized; Vector3D x = up.Cross(z).Normalized;
Vector3D y = z.Cross(x); Vector3D y = z.Cross(x);
return new Matrix4x4( return new(
x.X, y.X, z.X, 0f, x.X, y.X, z.X, 0f,
x.Y, y.Y, z.Y, 0f, x.Y, y.Y, z.Y, 0f,
x.Z, y.Z, z.Z, 0f, x.Z, y.Z, z.Z, 0f,
@@ -302,15 +302,15 @@ public readonly struct Matrix4x4(
public static Matrix4x4 CreateLookMatrix(Vector3D position, Vector3D target, Vector3D up) public static Matrix4x4 CreateLookMatrix(Vector3D position, Vector3D target, Vector3D up)
{ {
Vector3D z = position.FromTo(target).Normalized; Vector3D f = (target - position).Normalized;
Vector3D x = up.Cross(z).Normalized; Vector3D s = f.Cross(up).Normalized;
Vector3D y = z.Cross(x); Vector3D u = s.Cross(f);
return new Matrix4x4( return new(
x.X, y.X, z.X, 0f, s.X, u.X, -f.X, 0f,
x.Y, y.Y, z.Y, 0f, s.Y, u.Y, -f.Y, 0f,
x.Z, y.Z, z.Z, 0f, s.Z, u.Z, -f.Z, 0f,
-x.Dot(position), -y.Dot(position), -z.Dot(position), 1f -s.Dot(position), -u.Dot(position), f.Dot(position), 1f
); );
} }
@@ -318,10 +318,10 @@ public readonly struct Matrix4x4(
{ {
float invDepth = 1f / (farPlane - nearPlane); float invDepth = 1f / (farPlane - nearPlane);
return new Matrix4x4( return new(
2f / width, 0f, 0f, 0f, 2f / width, 0f, 0f, 0f,
0f, -2f / height, 0f, 0f, 0f, -2f / height, 0f, 0f,
0f, 0f, invDepth, 0f, 0f, 0f, 1f * invDepth, 0f,
-1f, 1f, -nearPlane * invDepth, 1f -1f, 1f, -nearPlane * invDepth, 1f
); );
} }
@@ -330,24 +330,25 @@ public readonly struct Matrix4x4(
{ {
float invDepth = 1f / (farPlane - nearPlane); float invDepth = 1f / (farPlane - nearPlane);
return new Matrix4x4( return new(
2f / width, 0f, 0f, 0f, 2f / width, 0f, 0f, 0f,
0f, 2f / height, 0f, 0f, 0f, 2f / height, 0f, 0f,
0f, 0f, invDepth, 0f, 0f, 0f, 1f * invDepth, 0f,
0f, 0f, -nearPlane * invDepth, 1f 0f, 0f, -nearPlane * invDepth, 1f
); );
} }
public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfViewInRadians, float aspectRatio, float nearPlane, float farPlane) public static Matrix4x4 CreatePerspectiveFieldOfView(float fovRadians, float aspectRatio, float nearPlane, float farPlane)
{ {
float yScale = 1f / Math.Tan(fieldOfViewInRadians / 2f); float yScale = 1f / Math.Tan(fovRadians / 2f);
float xScale = yScale / aspectRatio; float xScale = yScale / aspectRatio;
float zRange = farPlane - nearPlane;
return new Matrix4x4( return new(
xScale, 0f, 0f, 0f, xScale, 0f, 0f, 0f,
0f, yScale, 0f, 0f, 0f, yScale, 0f, 0f,
0f, 0f, farPlane / (farPlane - nearPlane), 1f, 0f, 0f, -(farPlane + nearPlane) / zRange, -1f,
0f, 0f, -nearPlane * farPlane / (farPlane - nearPlane), 0f 0f, 0f, -(2f * nearPlane * farPlane) / zRange, 0f
); );
} }

View File

@@ -1,11 +1,12 @@
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Engine.Core; using Engine.Core;
namespace Engine.Integration.MonoGame; namespace Engine.Integration.MonoGame;
public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFrameUpdate, IPreDraw public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFrameUpdate, IPreDraw, IUpdate
{ {
public Event<MonoGameCamera2D> OnViewMatrixChanged { get; } = new(); public Event<MonoGameCamera2D> OnViewMatrixChanged { get; } = new();
public Event<MonoGameCamera2D> OnProjectionMatrixChanged { get; } = new(); public Event<MonoGameCamera2D> OnProjectionMatrixChanged { get; } = new();
@@ -91,12 +92,20 @@ public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFr
public void PreDraw() public void PreDraw()
{ {
ProjectionMatrix = Matrix.CreateOrthographicOffCenter(Viewport.X, Viewport.Width, Viewport.Height, Viewport.Y, 0, 1).FromXnaMatrix(); ProjectionMatrix = Matrix4x4.CreateOrthographicViewCentered(Viewport.Width, -Viewport.Height);
ViewMatrix = ViewMatrix =
Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, Transform.Position.Y, 0f)) * Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, Transform.Position.Y, 0f))
Matrix4x4.CreateRotationZ(Transform.Rotation * Math.DegreeToRadian) * .ApplyRotationZ(Transform.Rotation * Math.DegreeToRadian)
Matrix4x4.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) * .ApplyScale(Transform.Scale.X.Max(Transform.Scale.Y))
Matrix4x4.CreateScale(Zoom) * .ApplyScale(Zoom);
Matrix4x4.CreateTranslation(new Vector3D(Viewport.Width * .5f, Viewport.Height * .5f, 0f)); }
public void Update()
{
KeyboardInputs keyboardInputs = Universe.FindRequiredBehaviour<KeyboardInputs>();
if (keyboardInputs.IsPressed(Keys.Right)) Transform.Position += Transform.Right * Universe.Time.DeltaTime * 100;
if (keyboardInputs.IsPressed(Keys.Up)) Transform.Position += Transform.Up * Universe.Time.DeltaTime * 100;
if (keyboardInputs.IsPressed(Keys.Down)) Transform.Position += Transform.Down * Universe.Time.DeltaTime * 100;
if (keyboardInputs.IsPressed(Keys.Left)) Transform.Position += Transform.Left * Universe.Time.DeltaTime * 100;
} }
} }

View File

@@ -44,19 +44,11 @@ public class MonoGameTriangleBatch : Behaviour, ITriangleBatch, IFirstFrameUpdat
} }
public void Begin(Matrix4x4? view = null, Matrix4x4? projection = null) public void Begin(Matrix4x4? view = null, Matrix4x4? projection = null)
{
if (view != null)
this.view = view.Value.ToXnaMatrix();
else
this.view = Matrix.Identity;
if (projection != null)
this.projection = projection.Value.ToXnaMatrix();
else
{ {
Viewport viewport = graphicsDevice.Viewport; Viewport viewport = graphicsDevice.Viewport;
this.projection = Matrix.CreateOrthographicOffCenter(viewport.X, viewport.Width, viewport.Height, viewport.Y, 0, 1);
} this.view = (view ?? Matrix4x4.Identity).Transposed.ToXnaMatrix();
this.projection = (projection ?? Matrix4x4.CreateOrthographicViewCentered(viewport.Width, viewport.Height)).Transposed.ToXnaMatrix();
} }
public void End() => Flush(); public void End() => Flush();