Merge pull request #69143 from raulsntos/dotnet/projection-docs

C#: Add Projection documentation
This commit is contained in:
Ignacio Roldán Etcheverry 2022-11-25 01:21:59 +01:00 committed by GitHub
commit cdfef0c852
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,6 +3,14 @@ using System.Runtime.InteropServices;
namespace Godot
{
/// <summary>
/// A 4x4 matrix used for 3D projective transformations. It can represent transformations such as
/// translation, rotation, scaling, shearing, and perspective division. It consists of four
/// <see cref="Vector4"/> columns.
/// For purely linear transformations (translation, rotation, and scale), it is recommended to use
/// <see cref="Transform3D"/>, as it is more performant and has a lower memory footprint.
/// Used internally as <see cref="Camera3D"/>'s projection matrix.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Projection : IEquatable<Projection>
@ -59,48 +67,107 @@ namespace Godot
public Vector4 w;
/// <summary>
/// Constructs a projection from 4 vectors (matrix columns).
/// Access whole columns in the form of <see cref="Vector4"/>.
/// </summary>
/// <param name="x">The X column, or column index 0.</param>
/// <param name="y">The Y column, or column index 1.</param>
/// <param name="z">The Z column, or column index 2.</param>
/// <param name="w">The W column, or column index 3.</param>
public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w)
/// <param name="column">Which column vector.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="column"/> is not 0, 1, 2 or 3.
/// </exception>
public Vector4 this[int column]
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
readonly get
{
switch (column)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
case 3:
return w;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
{
switch (column)
{
case 0:
x = value;
return;
case 1:
y = value;
return;
case 2:
z = value;
return;
case 3:
w = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
/// <summary>
/// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
/// Access single values.
/// </summary>
/// <param name="transform">The <see cref="Transform3D"/>.</param>
public Projection(Transform3D transform)
/// <param name="column">Which column vector.</param>
/// <param name="row">Which row of the column.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3.
/// </exception>
public real_t this[int column, int row]
{
x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0);
y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0);
z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0);
w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1);
readonly get
{
switch (column)
{
case 0:
return x[row];
case 1:
return y[row];
case 2:
return z[row];
case 3:
return w[row];
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
{
switch (column)
{
case 0:
x[row] = value;
return;
case 1:
y[row] = value;
return;
case 2:
z[row] = value;
return;
case 3:
w[row] = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
/// <summary>
/// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>.
/// Creates a new <see cref="Projection"/> that projects positions from a depth range of
/// <c>-1</c> to <c>1</c> to one that ranges from <c>0</c> to <c>1</c>, and flips the projected
/// positions vertically, according to <paramref name="flipY"/>.
/// </summary>
/// <param name="proj">The <see cref="Projection"/>.</param>
public static explicit operator Transform3D(Projection proj)
{
return new Transform3D(
new Basis(
new Vector3(proj.x.x, proj.x.y, proj.x.z),
new Vector3(proj.y.x, proj.y.y, proj.y.z),
new Vector3(proj.z.x, proj.z.y, proj.z.z)
),
new Vector3(proj.w.x, proj.w.y, proj.w.z)
);
}
/// <param name="flipY">If the projection should be flipped vertically.</param>
/// <returns>The created projection.</returns>
public static Projection CreateDepthCorrection(bool flipY)
{
return new Projection(
@ -111,6 +178,12 @@ namespace Godot
);
}
/// <summary>
/// Creates a new <see cref="Projection"/> that scales a given projection to fit around
/// a given <see cref="AABB"/> in projection space.
/// </summary>
/// <param name="aabb">The AABB to fit the projection around.</param>
/// <returns>The created projection.</returns>
public static Projection CreateFitAabb(AABB aabb)
{
Vector3 min = aabb.Position;
@ -124,6 +197,25 @@ namespace Godot
);
}
/// <summary>
/// Creates a new <see cref="Projection"/> for projecting positions onto a head-mounted display with
/// the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor,
/// and depth clipping planes.
/// <paramref name="eye"/> creates the projection for the left eye when set to 1,
/// or the right eye when set to 2.
/// </summary>
/// <param name="eye">
/// The eye to create the projection for.
/// The left eye when set to 1, the right eye when set to 2.
/// </param>
/// <param name="aspect">The aspect ratio.</param>
/// <param name="intraocularDist">The distance between the eyes.</param>
/// <param name="displayWidth">The display width.</param>
/// <param name="displayToLens">The distance to the lens.</param>
/// <param name="oversample">The oversampling factor.</param>
/// <param name="zNear">The near clipping distance.</param>
/// <param name="zFar">The far clipping distance.</param>
/// <returns>The created projection.</returns>
public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar)
{
real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens;
@ -148,6 +240,17 @@ namespace Godot
}
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions in a frustum with
/// the given clipping planes.
/// </summary>
/// <param name="left">The left clipping distance.</param>
/// <param name="right">The right clipping distance.</param>
/// <param name="bottom">The bottom clipping distance.</param>
/// <param name="top">The top clipping distance.</param>
/// <param name="near">The near clipping distance.</param>
/// <param name="far">The far clipping distance.</param>
/// <returns>The created projection.</returns>
public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far)
{
if (right <= left)
@ -179,6 +282,18 @@ namespace Godot
);
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions in a frustum with
/// the given size, X:Y aspect ratio, offset, and clipping planes.
/// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
/// </summary>
/// <param name="size">The frustum size.</param>
/// <param name="aspect">The aspect ratio.</param>
/// <param name="offset">The offset to apply.</param>
/// <param name="near">The near clipping distance.</param>
/// <param name="far">The far clipping distance.</param>
/// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
/// <returns>The created projection.</returns>
public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov)
{
if (!flipFov)
@ -188,6 +303,11 @@ namespace Godot
return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far);
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions into the given <see cref="Rect2"/>.
/// </summary>
/// <param name="rect">The Rect2 to project positions into.</param>
/// <returns>The created projection.</returns>
public static Projection CreateLightAtlasRect(Rect2 rect)
{
return new Projection(
@ -198,6 +318,17 @@ namespace Godot
);
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with
/// the given clipping planes.
/// </summary>
/// <param name="left">The left clipping distance.</param>
/// <param name="right">The right clipping distance.</param>
/// <param name="bottom">The bottom clipping distance.</param>
/// <param name="top">The top clipping distance.</param>
/// <param name="zNear">The near clipping distance.</param>
/// <param name="zFar">The far clipping distance.</param>
/// <returns>The created projection.</returns>
public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar)
{
Projection proj = Projection.Identity;
@ -211,6 +342,17 @@ namespace Godot
return proj;
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions using an orthogonal projection with
/// the given size, X:Y aspect ratio, and clipping planes.
/// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
/// </summary>
/// <param name="size">The frustum size.</param>
/// <param name="aspect">The aspect ratio.</param>
/// <param name="zNear">The near clipping distance.</param>
/// <param name="zFar">The far clipping distance.</param>
/// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
/// <returns>The created projection.</returns>
public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
{
if (!flipFov)
@ -220,6 +362,17 @@ namespace Godot
return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar);
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with
/// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes.
/// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
/// </summary>
/// <param name="fovyDegrees">The vertical field of view (in degrees).</param>
/// <param name="aspect">The aspect ratio.</param>
/// <param name="zNear">The near clipping distance.</param>
/// <param name="zFar">The far clipping distance.</param>
/// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
/// <returns>The created projection.</returns>
public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov)
{
if (flipFov)
@ -249,6 +402,27 @@ namespace Godot
return proj;
}
/// <summary>
/// Creates a new <see cref="Projection"/> that projects positions using a perspective projection with
/// the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances.
/// The projection is adjusted for a head-mounted display with the given distance between eyes and distance
/// to a point that can be focused on.
/// <paramref name="eye"/> creates the projection for the left eye when set to 1,
/// or the right eye when set to 2.
/// <paramref name="flipFov"/> determines whether the projection's field of view is flipped over its diagonal.
/// </summary>
/// <param name="fovyDegrees">The vertical field of view (in degrees).</param>
/// <param name="aspect">The aspect ratio.</param>
/// <param name="zNear">The near clipping distance.</param>
/// <param name="zFar">The far clipping distance.</param>
/// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param>
/// <param name="eye">
/// The eye to create the projection for.
/// The left eye when set to 1, the right eye when set to 2.
/// </param>
/// <param name="intraocularDist">The distance between the eyes.</param>
/// <param name="convergenceDist">The distance to a point of convergence that can be focused on.</param>
/// <returns>The created projection.</returns>
public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist)
{
if (flipFov)
@ -286,6 +460,13 @@ namespace Godot
return proj * cm;
}
/// <summary>
/// Returns a scalar value that is the signed factor by which areas are scaled by this matrix.
/// If the sign is negative, the matrix flips the orientation of the area.
/// The determinant can be used to calculate the invertibility of a matrix or solve linear systems
/// of equations involving the matrix, among other applications.
/// </summary>
/// <returns>The determinant calculated from this projection.</returns>
public readonly real_t Determinant()
{
return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x -
@ -302,12 +483,20 @@ namespace Godot
x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w;
}
/// <summary>
/// Returns the X:Y aspect ratio of this <see cref="Projection"/>'s viewport.
/// </summary>
/// <returns>The aspect ratio from this projection's viewport.</returns>
public readonly real_t GetAspect()
{
Vector2 vpHe = GetViewportHalfExtents();
return vpHe.x / vpHe.y;
}
/// <summary>
/// Returns the horizontal field of view of the projection (in degrees).
/// </summary>
/// <returns>The horizontal field of view of this projection.</returns>
public readonly real_t GetFov()
{
Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized();
@ -322,11 +511,22 @@ namespace Godot
}
}
/// <summary>
/// Returns the vertical field of view of the projection (in degrees) associated with
/// the given horizontal field of view (in degrees) and aspect ratio.
/// </summary>
/// <param name="fovx">The horizontal field of view (in degrees).</param>
/// <param name="aspect">The aspect ratio.</param>
/// <returns>The vertical field of view of this projection.</returns>
public static real_t GetFovy(real_t fovx, real_t aspect)
{
return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0);
}
/// <summary>
/// Returns the factor by which the visible level of detail is scaled by this <see cref="Projection"/>.
/// </summary>
/// <returns>The level of detail factor for this projection.</returns>
public readonly real_t GetLodMultiplier()
{
if (IsOrthogonal())
@ -341,6 +541,12 @@ namespace Godot
}
}
/// <summary>
/// Returns the number of pixels with the given pixel width displayed per meter, after
/// this <see cref="Projection"/> is applied.
/// </summary>
/// <param name="forPixelWidth">The width for each pixel (in meters).</param>
/// <returns>The number of pixels per meter.</returns>
public readonly int GetPixelsPerMeter(int forPixelWidth)
{
Vector3 result = this * new Vector3(1, 0, -1);
@ -348,6 +554,15 @@ namespace Godot
return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth);
}
/// <summary>
/// Returns the clipping plane of this <see cref="Projection"/> whose index is given
/// by <paramref name="plane"/>.
/// <paramref name="plane"/> should be equal to one of <see cref="Planes.Near"/>,
/// <see cref="Planes.Far"/>, <see cref="Planes.Left"/>, <see cref="Planes.Top"/>,
/// <see cref="Planes.Right"/>, or <see cref="Planes.Bottom"/>.
/// </summary>
/// <param name="plane">The kind of clipping plane to get from the projection.</param>
/// <returns>The clipping plane of this projection.</returns>
public readonly Plane GetProjectionPlane(Planes plane)
{
Plane newPlane = plane switch
@ -364,28 +579,49 @@ namespace Godot
return newPlane.Normalized();
}
/// <summary>
/// Returns the dimensions of the far clipping plane of the projection, divided by two.
/// </summary>
/// <returns>The half extents for this projection's far plane.</returns>
public readonly Vector2 GetFarPlaneHalfExtents()
{
var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
return new Vector2(res.Value.x, res.Value.y);
}
/// <summary>
/// Returns the dimensions of the viewport plane that this <see cref="Projection"/>
/// projects positions onto, divided by two.
/// </summary>
/// <returns>The half extents for this projection's viewport plane.</returns>
public readonly Vector2 GetViewportHalfExtents()
{
var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top));
return new Vector2(res.Value.x, res.Value.y);
}
/// <summary>
/// Returns the distance for this <see cref="Projection"/> beyond which positions are clipped.
/// </summary>
/// <returns>The distance beyond which positions are clipped.</returns>
public readonly real_t GetZFar()
{
return GetProjectionPlane(Planes.Far).D;
}
/// <summary>
/// Returns the distance for this <see cref="Projection"/> before which positions are clipped.
/// </summary>
/// <returns>The distance before which positions are clipped.</returns>
public readonly real_t GetZNear()
{
return -GetProjectionPlane(Planes.Near).D;
}
/// <summary>
/// Returns a copy of this <see cref="Projection"/> with the signs of the values of the Y column flipped.
/// </summary>
/// <returns>The flipped projection.</returns>
public readonly Projection FlippedY()
{
Projection proj = this;
@ -393,6 +629,13 @@ namespace Godot
return proj;
}
/// <summary>
/// Returns a <see cref="Projection"/> with the near clipping distance adjusted to be
/// <paramref name="newZNear"/>.
/// Note: The original <see cref="Projection"/> must be a perspective projection.
/// </summary>
/// <param name="newZNear">The near clipping distance to adjust the projection to.</param>
/// <returns>The adjusted projection.</returns>
public readonly Projection PerspectiveZNearAdjusted(real_t newZNear)
{
Projection proj = this;
@ -404,6 +647,12 @@ namespace Godot
return proj;
}
/// <summary>
/// Returns a <see cref="Projection"/> with the X and Y values from the given <see cref="Vector2"/>
/// added to the first and second values of the final column respectively.
/// </summary>
/// <param name="offset">The offset to apply to the projection.</param>
/// <returns>The offseted projection.</returns>
public readonly Projection JitterOffseted(Vector2 offset)
{
Projection proj = this;
@ -412,6 +661,11 @@ namespace Godot
return proj;
}
/// <summary>
/// Returns a <see cref="Projection"/> that performs the inverse of this <see cref="Projection"/>'s
/// projective transformation.
/// </summary>
/// <returns>The inverted projection.</returns>
public readonly Projection Inverse()
{
Projection proj = this;
@ -535,11 +789,70 @@ namespace Godot
return proj;
}
/// <summary>
/// Returns <see langword="true"/> if this <see cref="Projection"/> performs an orthogonal projection.
/// </summary>
/// <returns>If the projection performs an orthogonal projection.</returns>
public readonly bool IsOrthogonal()
{
return w.w == (real_t)1.0;
}
// Constants
private static readonly Projection _zero = new Projection(
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0)
);
private static readonly Projection _identity = new Projection(
new Vector4(1, 0, 0, 0),
new Vector4(0, 1, 0, 0),
new Vector4(0, 0, 1, 0),
new Vector4(0, 0, 0, 1)
);
/// <summary>
/// Zero projection, a projection with all components set to <c>0</c>.
/// </summary>
/// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value>
public static Projection Zero { get { return _zero; } }
/// <summary>
/// The identity projection, with no distortion applied.
/// This is used as a replacement for <c>Projection()</c> in GDScript.
/// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero.
/// </summary>
/// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value>
public static Projection Identity { get { return _identity; } }
/// <summary>
/// Constructs a projection from 4 vectors (matrix columns).
/// </summary>
/// <param name="x">The X column, or column index 0.</param>
/// <param name="y">The Y column, or column index 1.</param>
/// <param name="z">The Z column, or column index 2.</param>
/// <param name="w">The W column, or column index 3.</param>
public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
/// <summary>
/// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
/// </summary>
/// <param name="transform">The <see cref="Transform3D"/>.</param>
public Projection(Transform3D transform)
{
x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0);
y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0);
z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0);
w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1);
}
/// <summary>
/// Composes these two projections by multiplying them
/// together. This has the effect of applying the right
@ -646,127 +959,41 @@ namespace Godot
}
/// <summary>
/// Access whole columns in the form of <see cref="Vector4"/>.
/// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>.
/// </summary>
/// <param name="column">Which column vector.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="column"/> is not 0, 1, 2 or 3.
/// </exception>
public Vector4 this[int column]
/// <param name="proj">The <see cref="Projection"/>.</param>
public static explicit operator Transform3D(Projection proj)
{
readonly get
{
switch (column)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
case 3:
return w;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
{
switch (column)
{
case 0:
x = value;
return;
case 1:
y = value;
return;
case 2:
z = value;
return;
case 3:
w = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
/// <summary>
/// Access single values.
/// </summary>
/// <param name="column">Which column vector.</param>
/// <param name="row">Which row of the column.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3.
/// </exception>
public real_t this[int column, int row]
{
readonly get
{
switch (column)
{
case 0:
return x[row];
case 1:
return y[row];
case 2:
return z[row];
case 3:
return w[row];
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
{
switch (column)
{
case 0:
x[row] = value;
return;
case 1:
y[row] = value;
return;
case 2:
z[row] = value;
return;
case 3:
w[row] = value;
return;
default:
throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
// Constants
private static readonly Projection _zero = new Projection(
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0),
new Vector4(0, 0, 0, 0)
);
private static readonly Projection _identity = new Projection(
new Vector4(1, 0, 0, 0),
new Vector4(0, 1, 0, 0),
new Vector4(0, 0, 1, 0),
new Vector4(0, 0, 0, 1)
return new Transform3D(
new Basis(
new Vector3(proj.x.x, proj.x.y, proj.x.z),
new Vector3(proj.y.x, proj.y.y, proj.y.z),
new Vector3(proj.z.x, proj.z.y, proj.z.z)
),
new Vector3(proj.w.x, proj.w.y, proj.w.z)
);
}
/// <summary>
/// Zero projection, a projection with all components set to <c>0</c>.
/// Returns <see langword="true"/> if the projection is exactly equal
/// to the given object (<see paramref="obj"/>).
/// </summary>
/// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value>
public static Projection Zero { get { return _zero; } }
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
public override readonly bool Equals(object obj)
{
return obj is Projection other && Equals(other);
}
/// <summary>
/// The identity projection, with no distortion applied.
/// This is used as a replacement for <c>Projection()</c> in GDScript.
/// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero.
/// Returns <see langword="true"/> if the projections are exactly equal.
/// </summary>
/// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value>
public static Projection Identity { get { return _identity; } }
/// <param name="other">The other projection.</param>
/// <returns>Whether or not the projections are exactly equal.</returns>
public readonly bool Equals(Projection other)
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
/// <summary>
/// Serves as the hash function for <see cref="Projection"/>.
@ -797,26 +1024,5 @@ namespace Godot
$"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" +
$"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n";
}
/// <summary>
/// Returns <see langword="true"/> if the projection is exactly equal
/// to the given object (<see paramref="obj"/>).
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the vector and the object are equal.</returns>
public override readonly bool Equals(object obj)
{
return obj is Projection other && Equals(other);
}
/// <summary>
/// Returns <see langword="true"/> if the projections are exactly equal.
/// </summary>
/// <param name="other">The other projection.</param>
/// <returns>Whether or not the projections are exactly equal.</returns>
public readonly bool Equals(Projection other)
{
return x == other.x && y == other.y && z == other.z && w == other.w;
}
}
}